parser fixes, infix operator sequence parsing node

This commit is contained in:
ProgramSnail 2025-06-18 23:41:27 +03:00
parent b60602055b
commit e022ff03b3
4 changed files with 4029 additions and 3453 deletions

View file

@ -52,13 +52,14 @@ grammar Lama;
import java.util.Optional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.strings.TruffleString;
import org.programsnail.truffle_lama.LamaLanguage;
import org.programsnail.truffle_lama.nodes.LamaExpressionNode;
import org.programsnail.truffle_lama.nodes.LamaRootNode;
import org.programsnail.truffle_lama.nodes.pattern.LamaPattern;
}
@lexer::header
@ -94,7 +95,7 @@ private static void throwParseError(Source source, int line, int charPositionInL
throw new LamaParseError(source, line, col, length, String.format("Error(s) parsing script:%n" + location + message));
}
public static LamaExpressionNode parseLama(LamaLanguage language, Source source) {
public static LamaRootNode parseLama(LamaLanguage language, Source source) {
LamaLexer lexer = new LamaLexer(CharStreams.fromString(source.getCharacters().toString()));
LamaParser parser = new LamaParser(new CommonTokenStream(lexer));
lexer.removeErrorListeners();
@ -113,26 +114,28 @@ public static LamaExpressionNode parseLama(LamaLanguage language, Source source)
lama returns [LamaExpressionNode result]:
/* (import_expression)* */
scope_expression { $result = $scope_expression.result; }
scope_expression[false] { $result = $scope_expression.result; factory.setRootExpr($result); }
EOF;
//import_expression : 'import' UIDENT ';';
scope_expression returns [LamaExpressionNode result]:
definition { $result = $expression.result; }
scope_expression[boolean do_scope] returns [LamaExpressionNode result]
: { if (do_scope) { factory.enterScope(); } }
(definition { $result = $expression.result; }
(
definition { $result = factory.createSeqNode($result, $expression.result); }
)* (
expression { $result = factory.createSeqNode($result, $expression.result); }
)?
| expression { $result = $expression.result; }
| expression { $result = $expression.result; })
{ if (do_scope) { factory.exitScope(); } }
;
definition returns [LamaExpressionNode result]:
variable_definition { $result = $variable_definition.result; }
| function_definition { $result = $function_definition.result; }
;
// | infix_definition;
;
// | infix_definition { $result = $infix_definition.result; };
//
@ -144,32 +147,42 @@ variable_definition returns [LamaExpressionNode result]
variable_definition_sequence[is_public] { $result = $variable_definition_sequence.result; }
;
variable_definition_sequence[boolean is_public] returns [LamaExpressionNode result]:
variable_definition_item { $result = factory.createVarNode($variable_definition_item.name, $variable_definition_item.expr); }
variable_definition_item { $result = factory.createAssignVarNode($variable_definition_item.name, $variable_definition_item.expr); }
(','
variable_definition_item { $result = factory.createSeqNode($result, factory.createVarNode($variable_definition_item.name, $variable_definition_item.expr)); }
variable_definition_item { $result = factory.createSeqNode($result, factory.createAssignVarNode($variable_definition_item.name, $variable_definition_item.expr)); }
)* ';';
variable_definition_item returns [TruffleString name, Optional<LamaExpressionNode> expr]
: { $expr = Optional.empty(); }
variable_definition_item returns [Token name, LamaExpressionNode expr]
: { $expr = null; }
LIDENT { $name = $LIDENT; }
('='
basic_expression { $expr = Optional.of($basic_expression.result); }
basic_expression { $expr = $basic_expression.result; }
)?;
function_definition returns [LamaExpressionNode result] // TODO: scopes
: { boolean is_public = false; }
function_definition returns [LamaExpressionNode result]
: {
boolean is_public = false;
List<Token> args = new ArrayList<Token>();
factory.enterScope(LamaNodeFactory.LexicalScope.Kind.FUNCTION);
}
(
'public' { is_public = true; }
)? 'fun' LIDENT '(' (function_arguments)? ')' function_body
{ $result = factory.defineFunction($LIDENT, $function_arguments.args, $function_body.result); }
)? 'fun' LIDENT '(' (
function_arguments { args = $function_arguments.args; factory.addFunctionArguments(args); }
)? ')' function_body
{
$result = factory.createClosureNode($LIDENT, $function_body.result, args.size()); // create lambda for the function
factory.exitScope(); // TODO: create exit node to create vars ??
$result = factory.createAssignVarNode($LIDENT, $result); // create global function: out of the created scope
}
;
function_arguments returns [List<TruffleString> args]
: { $args = new ArrayList<TruffleString>(); }
function_arguments returns [List<Token> args]
: { $args = new ArrayList<Token>(); }
LIDENT { $args.addLast($LIDENT); }
(','
LIDENT { $args.addLast($LIDENT); }
)*;
function_body returns [LamaExpressionNode result]:
'{'
scope_expression { $result = $scope_expression.result; }
scope_expression[true] { $result = $scope_expression.result; }
'}';
//
@ -185,14 +198,14 @@ expression returns [LamaExpressionNode result]:
basic_expression { $result = $basic_expression.result; }
(';'
expression { $result = factory.createSeqNode($result, $expression.result); }
)?; // TODO: additional things, exit scope ??
)?;
basic_expression returns [LamaExpressionNode result]: binary_expression { $result = $binary_expression.result; };
binary_expression returns [LamaExpressionNode result]:
postfix_expression { $result = $postfix_expression.result; }
(
any_infix
postfix_expression { $result = factory.createBinopNode($any_infix.result, $result, $postfix_expression.result); }
)*;
)*; // TODO: replace with custom sequence parser (with infixity)
postfix_expression returns [LamaExpressionNode result]
: { boolean with_minus = false; }
(
@ -202,14 +215,24 @@ postfix_expression returns [LamaExpressionNode result]
(
postfix {
if ($postfix.access_index.isPresent()) {
$result = factory.createElemNode($result, ($postfix.access_index.get())); // TODO: or RefElem node
$result = factory.createElemValueNode($result, $postfix.access_index.get());
// TODO: choose between elem and ref
} else {
$result = factory.createCallNode($result, $postfix.args);
}
}
)*; // TODO: elem or elem ref for access node ??
)*
{
if (with_minus) {
$result = factory.createBinopNode(
$MINUS,
factory.createValueConstNode($MINUS, 0),
$result);
}
}
;
postfix returns [List<LamaExpressionNode> args, Optional<LamaExpressionNode> access_index]
: { $args = new ArrayList<LamaExpressionNode>(); $access_index = Option.empty(); }
: { $args = new ArrayList<LamaExpressionNode>(); $access_index = Optional.empty(); }
'('
expression { $args.addLast($expression.result); }
(','
@ -218,7 +241,7 @@ postfix returns [List<LamaExpressionNode> args, Optional<LamaExpressionNode> acc
')'
| '(' ')'
| '['
expression { $access_index = Option.of($expression.result); }
expression { $access_index = Optional.of($expression.result); }
']'
;
@ -226,14 +249,25 @@ primary returns [LamaExpressionNode result]:
DECIMAL_LITERAL { $result = factory.createConstNode($DECIMAL_LITERAL); } // minus - inside decimal literal definition
| STRING_LITERAL { $result = factory.createStringNode($STRING_LITERAL); }
| CHAR_LITERAL { $result = factory.createCharConstNode($CHAR_LITERAL); }
| LIDENT { $result = factory.createRefNode($LIDENT); }
| LIDENT { $result = factory.createValueNode($LIDENT); } // TODO: choose between value and ref
| tok='true' { $result = factory.createValueConstNode($tok, 1); }
| tok='false' { $result = factory.createValueConstNode($tok, 0); }
| 'infix' any_infix { $result = factory.createRefNode($any_infix.result); }
| 'fun' '(' function_arguments ')' function_body
{ $result = factory.createClosureNode($function_arguments.args, $function_body.result); } // TODO: scopes
| 'skip' { $result = factory.createSkipNode(); }
| '(' scope_expression ')' { $result = $scope_expression.result; } // add some scope for correct attribution ??
| 'infix' any_infix { $result = factory.createValueNode($any_infix.result); }
| tok='fun' '('
{
List<Token> args = new ArrayList<Token>();
factory.enterScope(LamaNodeFactory.LexicalScope.Kind.INNER_CLOSURE);
}
function_arguments { args = $function_arguments.args; factory.addFunctionArguments(args); }
// TODO: make optional ??
')'
function_body
{
$result = factory.createClosureNode($tok, $function_body.result, args.size());
factory.exitScope(); // TODO: create exit node to create vars ??
}
| tok='skip' { $result = factory.createSkipNode($tok); }
| '(' scope_expression[true] ')' { $result = $scope_expression.result; } // TODO: check
| list_expression { $result = $list_expression.result; }
| array_expression { $result = $array_expression.result; }
| s_expression { $result = $s_expression.result; }
@ -282,27 +316,31 @@ s_expression returns [LamaExpressionNode result]
if_expression returns [LamaExpressionNode result]
: { LamaExpressionNode do_else = null; }
'if' expression 'then' scope_expression (
'if' expression 'then' scope_expression[true]
(
else_part { do_else = $else_part.result; }
)? 'fi'
{ $result = factory.createIfNode($expression.result, $scope_expression.result, do_else); }
;
else_part returns [LamaExpressionNode result]:
'elif' { LamaExpressionNode do_else = null; } expression 'then' scope_expression (
'elif' { LamaExpressionNode do_else = null; } expression 'then' scope_expression[true] (
else_part { do_else = $else_part.result; }
)? { $result = factory.createIfNode($expression.result, $scope_expression.result, do_else); }
| 'else' scope_expression { $result = $scope_expression.result; };
| 'else' scope_expression[true] { $result = $scope_expression.result; };
//
while_do_expression returns [LamaExpressionNode result]: 'while' expression 'do' scope_expression 'od'
while_do_expression returns [LamaExpressionNode result]: 'while' expression 'do' scope_expression[true] 'od'
{ $result = factory.createWhileNode($expression.result, $scope_expression.result); };
do_while_expression returns [LamaExpressionNode result]: 'do' scope_expression 'while' expression 'od'
do_while_expression returns [LamaExpressionNode result]: 'do' scope_expression[true] 'while' expression 'od'
{ $result = factory.createDoWhileNode($expression.result, $scope_expression.result); };
for_expression returns [LamaExpressionNode result]:
'for' init=scope_expression ',' cond=expression ',' inc=expression 'do' expr=scope_expression 'od'
// TODO: add scope, etc.
{ $result = factory.createSeqNode($init.result, factory.createWhileNode($cond.result, factory.createSeqNode($expr.result, $inc.result))); }
'for' { factory.enterScope(); }
init=scope_expression[false] ',' cond=expression ',' inc=expression 'do' expr=scope_expression[true] 'od'
{
$result = factory.createSeqNode($init.result, factory.createWhileNode($cond.result, factory.createSeqNode($expr.result, $inc.result)));
factory.exitScope();
}
;
//
@ -311,7 +349,7 @@ pattern returns [LamaPattern result]:
cons_pattern { $result = $cons_pattern.result; }
| simple_pattern { $result = $simple_pattern.result; }
;
cons_pattern returns [LamaPattern result]: simple_pattern ':' pattern { $result = factory.createSexpPattern("cons", {$simple_pattern.result, $pattern.result}); };
cons_pattern returns [LamaPattern result]: simple_pattern ':' pattern { $result = factory.createSexpConsPattern($simple_pattern.result, $pattern.result); };
simple_pattern returns [LamaPattern result]:
wildcard_pattern { $result = $wildcard_pattern.result; }
| s_expr_pattern { $result = $s_expr_pattern.result; }
@ -322,16 +360,16 @@ simple_pattern returns [LamaPattern result]:
('@'
pattern { pat = $pattern.result; }
)?
{ $result = factory.createNamedPattern($LIDENT, Objects.requireNonNullElse(pat, factory.createWildcardPattern()); }
{ $result = factory.createNamedPattern($LIDENT, Objects.requireNonNullElse(pat, factory.createWildcardPattern())); }
| { boolean is_negative = false; }
(
MINUS { is_negative = true; }
)?
DECIMAL_LITERAL { $result = is_negative ? factory.createNegativeConstPattern($DECIMAL_LITERAL) : factory.createConstPattern($DECIMAL_LITERAL); }
| STRING_LITERAL { $result = factory.createStringPattern(LamaStrings.convertStringLiteral($STRING_LITERAL)); }
| CHAR_LITERAL { $result = factory.createConstPattern(LamaStrings.convertCharLiteral($CHAR_LITERAL)); }
| 'true' { $result = factory.createConstPattern(1); }
| 'false' { $result = factory.createConstPattern(0); }
| STRING_LITERAL { $result = factory.createStringPattern($STRING_LITERAL); }
| CHAR_LITERAL { $result = factory.createConstPattern($CHAR_LITERAL); }
| tok='true' { $result = factory.createValueConstPattern($tok, 1); }
| tok='false' { $result = factory.createValueConstPattern($tok, 0); }
| '#' 'box' { $result = factory.createBoxedPattern(); }
| '#' 'val' { $result = factory.createUnBoxedPattern(); }
| '#' 'str' { $result = factory.createStringTagPattern(); }
@ -368,7 +406,7 @@ list_pattern returns [LamaPattern result]
'{' (
pattern { elems.addLast($pattern.result); }
(','
pattern { elems.addLast($pattern.result); } //FIXME: wrong order
pattern { elems.addLast($pattern.result); }
)*)?
'}'
{ $result = factory.createListSexpPattern(elems); }
@ -380,18 +418,20 @@ case_expression returns [LamaExpressionNode result]:
'case' expression 'of' case_branches 'esac' { $result = factory.createCaseNode($expression.result, $case_branches.pats, $case_branches.exprs); }
;
case_branches returns [List<LamaPattern> pats, List<LamaExpressionNode> exprs]
: { $pats = new ArrayList<LamaPattern>(); $exprs = new ArrayList<LamaExpressionNode> exprs; }
: { $pats = new ArrayList<LamaPattern>(); $exprs = new ArrayList<LamaExpressionNode>(); }
case_branch { $pats.addLast($case_branch.pat); $exprs.addLast($case_branch.expr); }
('|'
case_branch { $pats.addLast($case_branch.pat); $exprs.addLast($case_branch.expr); }
)*;
case_branch returns [LamaPattern pat, LamaExpressionNode expr]:
case_branch returns [LamaPattern pat, LamaExpressionNode expr]
: { factory.enterScope(); }
pattern { $pat = $pattern.result; }
'->'
scope_expression { $expr = $scope_expression.result; }
scope_expression[false] { $expr = $scope_expression.result; }
{ factory.exitScope(); }
;
any_infix returns [String result]:
any_infix returns [Token result]:
INFIX { $result = $INFIX; }
| MINUS { $result = $MINUS; }
;

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,5 @@
package org.programsnail.truffle_lama.parser;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.source.Source;
@ -9,6 +8,7 @@ import org.antlr.v4.runtime.Token;
import org.programsnail.truffle_lama.LamaLanguage;
import org.programsnail.truffle_lama.LamaStrings;
import org.programsnail.truffle_lama.nodes.LamaExpressionNode;
import org.programsnail.truffle_lama.nodes.LamaRootNode;
import org.programsnail.truffle_lama.nodes.controlflow.LamaCaseNode;
import org.programsnail.truffle_lama.nodes.controlflow.LamaDoWhileNode;
import org.programsnail.truffle_lama.nodes.controlflow.LamaIfNode;
@ -132,7 +132,7 @@ public class LamaNodeFactory {
// ---
public boolean isGlobal() {
return outer == null;
return top == null;
}
public boolean isFramed() {
@ -261,31 +261,102 @@ public class LamaNodeFactory {
private final Source source;
private final TruffleString sourceString;
/* State while parsing an expr. */
private LexicalScope lexicalScope;
private final LamaLanguage language;
private LamaExpressionNode rootExpr;
private enum InfixKind {
LEFT,
RIGHT,
NONE,
}
private Map<String, Integer> infixPriorities;
private Map<String, InfixKind> infixKinds;
public LamaNodeFactory(LamaLanguage language, Source source) {
this.language = language;
this.source = source;
this.sourceString = LamaStrings.fromJavaString(source.getCharacters().toString());
lexicalScope = new LexicalScope(null, LexicalScope.Kind.FUNCTION); // same to top level
this.lexicalScope = new LexicalScope(null, LexicalScope.Kind.FUNCTION); // same to top level
infixPriorities = new HashMap<>();
infixKinds = new HashMap<>();
}
// ---
public void enterScope() {
enterScope(LexicalScope.Kind.INNER_SCOPE);
}
public void enterScope(LexicalScope.Kind kind) {
lexicalScope = new LexicalScope(lexicalScope, kind);
}
public void exitScope() {
// TODO: save vars to clear them & create corresponding scope node ??
lexicalScope = lexicalScope.getOuter();
}
// ---
// TODO: custom infixes: non-0integer indices (at, before, after)
// NOTE: very slow implementation, can be optimized
LamaExpressionNode createInfixArrayRecursive(List<Token> oprs, List<LamaExpressionNode> exprs) {
assert oprs.size() == exprs.size() - 1;
if (exprs.size() == 1) {
return exprs.getFirst();
}
if (exprs.size() == 2) {
return createAnyBinopNode(oprs.getFirst(), exprs.getFirst(), exprs.getLast());
}
int splitIndex = 0;
{
String splitOpr = null;
int splitPriority = 0;
InfixKind splitKind = null;
for (int i = 0; i < oprs.size(); ++i) {
String currentSplitOpr = oprs.get(i).getText();
if (Objects.equals(splitOpr, currentSplitOpr)) {
if (splitKind == InfixKind.RIGHT) { // TODO: check left or right
splitIndex = i;
continue;
}
if (splitKind == InfixKind.NONE) {
throw new LamaException("Operator '" + splitOpr + "' can't be chained");
}
}
Integer currentSplitPriority = infixPriorities.get(currentSplitOpr);
if (currentSplitPriority == null) {
throw new LamaException("Unknown operator '" + splitOpr + "' (split priority)");
}
if (splitOpr == null || currentSplitPriority > splitPriority) { // TODO: check < or >
splitOpr = currentSplitOpr;
splitPriority = currentSplitPriority;
splitKind = infixKinds.get(splitOpr);
if (splitKind == null) {
throw new LamaException("Unknown operator '" + splitOpr + "' (split kind)");
}
}
}
}
LamaExpressionNode leftExpr = createInfixArrayRecursive(oprs.subList(0, splitIndex), exprs.subList(0, splitIndex + 1));
LamaExpressionNode rightExpr = createInfixArrayRecursive(oprs.subList(splitIndex + 1, oprs.size()), exprs.subList(splitIndex + 1, exprs.size()));
return createAnyBinopNode(oprs.get(splitIndex), leftExpr, rightExpr);
}
// ---
// TODO: add to parser
public void AddFunctionArguments(Token[] args) {
public void addFunctionArguments(List<Token> args) {
for (Token arg : args) {
lexicalScope.addArgument(arg.getText());
}
@ -327,7 +398,7 @@ public class LamaNodeFactory {
public LamaExpressionNode createVarNode(Token token) {
String name = token.getText();
int slot = lexicalScope.add(name); // TODO: check if not arg ??
int slot = lexicalScope.add(name);
return addSrcFromToken(lexicalScope.isGlobal() /*global scope*/
? new LamaGlobalVarNode(name)
: new LamaLocalVarNode(slot), token);
@ -340,6 +411,10 @@ public class LamaNodeFactory {
// TODO: fix assignment in parser
public LamaExpressionNode createAssignVarNode(Token token, LamaExpressionNode value) {
var definition = createVarNode(token);
if (value == null) {
return definition;
}
var reference = createRefNode(token);
var assignment = createAssignNode(reference, value);
return createSeqNode(definition, assignment);
@ -353,11 +428,14 @@ public class LamaNodeFactory {
public LamaExpressionNode createAnyBinopNode(Token opToken, LamaExpressionNode left, LamaExpressionNode right) {
String op = opToken.getText();
return switch (op) {
// case ":" -> // TODO: cons
case ":=" -> createAssignNode(left, right);
case "+", "-", "/", "%",
"<", "<=", ">", ">=", "==", "!=",
"&&", "!!" -> createBinopNode(opToken, left, right);
default -> createCallNode(createRefNode(opToken), new LamaExpressionNode[]{left, right});
default -> createCallNode(
createRefNode(opToken),
List.of(new LamaExpressionNode[]{left, right}));
};
}
@ -366,6 +444,11 @@ public class LamaNodeFactory {
return addSrcFromNodes(LamaBinopNodeGen.create(left, right, op), left, right);
}
public LamaExpressionNode createElemValueNode(LamaExpressionNode array, LamaExpressionNode index) {
// TODO: replace with separate node for more efficiency
return createElemRefOrValueNode(array, index, true);
}
public LamaExpressionNode createElemRefOrValueNode(LamaExpressionNode array, LamaExpressionNode index, boolean doUnref) {
return addUnref(createElemRefNode(array, index), doUnref);
}
@ -374,8 +457,16 @@ public class LamaNodeFactory {
return addSrcFromNodes(LamaElemRefNodeGen.create(array, index), array, index);
}
public LamaExpressionNode createCallNode(LamaExpressionNode func, LamaExpressionNode[] args) {
return addSrcFromNodes(new LamaCallNode(func, args), func, args.length > 0 ? args[args.length - 1] : func);
public LamaExpressionNode createCallNode(LamaExpressionNode func, List<LamaExpressionNode> args) {
return addSrcFromNodes(
new LamaCallNode(func, args.toArray(new LamaExpressionNode[0])),
func,
args.isEmpty() ? func : args.getLast());
}
public LamaExpressionNode createValueNode(Token token) {
// TODO: replace with separate node for more efficiency
return createRefOrValueNode(token, true);
}
public LamaExpressionNode createRefOrValueNode(Token token, boolean doUnref) {
@ -407,27 +498,28 @@ public class LamaNodeFactory {
return addSrcFromToken(new LamaSkipNode(), token);
}
public LamaExpressionNode createArrayNode(LamaExpressionNode[] elems) {
LamaExpressionNode result = new LamaArrayNode(elems);
return elems.length > 0 ? addSrcFromNodes(result, elems[0], elems[elems.length - 1]) : result;
public LamaExpressionNode createArrayNode(List<LamaExpressionNode> elems) {
LamaExpressionNode[] elemsArray = elems.toArray(new LamaExpressionNode[0]);
LamaExpressionNode result = new LamaArrayNode(elemsArray);
return elems.isEmpty() ? result : addSrcFromNodes(result, elems.getFirst(), elems.getLast());
}
// sexps-pairs with tag 'cons'
public LamaExpressionNode createListSexpNode(LamaExpressionNode[] elems) {
public LamaExpressionNode createListSexpNode(List<LamaExpressionNode> elems) {
LamaExpressionNode result = new LamaConstNode(0);
for (int i = elems.length - 1; i >= 0; --i) {
result = new LamaSexpNode(LamaStrings.fromJavaString("cons"), new LamaExpressionNode[]{elems[i], result});
for (int i = elems.size() - 1; i >= 0; --i) {
result = new LamaSexpNode(LamaStrings.fromJavaString("cons"), new LamaExpressionNode[]{elems.get(i), result});
}
return elems.length > 0 ? addSrcFromNodes(result, elems[0], elems[elems.length - 1]) : result;
return elems.isEmpty() ? result : addSrcFromNodes(result, elems.getFirst(), elems.getLast());
}
public LamaExpressionNode createSexpNode(Token tag, LamaExpressionNode[] elems) {
LamaExpressionNode result = new LamaSexpNode(LamaStrings.fromJavaString(tag.getText()), elems);
return elems.length > 0 ? addSrcFromNodes(result, elems[0]/*TODO: use tag instead*/, elems[elems.length - 1]) : addSrcFromToken(result, tag);
public LamaExpressionNode createSexpNode(Token tag, List<LamaExpressionNode> elems) {
LamaExpressionNode result = new LamaSexpNode(LamaStrings.fromJavaString(tag.getText()), elems.toArray(new LamaExpressionNode[0]));
return elems.isEmpty() ? addSrcFromToken(result, tag) : addSrcFromTokenAndNode(result, tag, elems.getLast());
}
public LamaExpressionNode createIfNode(LamaExpressionNode condition, LamaExpressionNode doThen, LamaExpressionNode doElse) {
return addSrcFromNodes(new LamaIfNode(condition, doThen, doElse), condition, doElse);
return addSrcFromNodes(new LamaIfNode(condition, doThen, doElse), condition, doElse == null ? doThen : doElse);
}
public LamaExpressionNode createWhileNode(LamaExpressionNode condition, LamaExpressionNode body) {
@ -438,10 +530,16 @@ public class LamaNodeFactory {
return addSrcFromNodes(new LamaDoWhileNode(condition, body), condition, body);
}
public LamaExpressionNode createCaseNode(LamaExpressionNode value, LamaPattern[] patterns, LamaExpressionNode[] exprs) {
assert patterns.length == exprs.length;
assert patterns.length > 0;
return addSrcFromNodes(new LamaCaseNode(value, patterns, exprs), value, exprs[exprs.length - 1]);
public LamaExpressionNode createCaseNode(LamaExpressionNode value, List<LamaPattern> patterns, List<LamaExpressionNode> exprs) {
assert patterns.size() == exprs.size();
assert !patterns.isEmpty();
return addSrcFromNodes(
new LamaCaseNode(
value,
patterns.toArray(new LamaPattern[0]),
exprs.toArray(new LamaExpressionNode[0])),
value,
exprs.getLast());
}
// ---
@ -450,19 +548,23 @@ public class LamaNodeFactory {
return new LamaWildcardPattern();
}
public LamaPattern createSexpPattern(Token tag, LamaPattern[] elems) {
return new LamaSexpPattern(LamaStrings.fromJavaString(tag.getText()), elems);
public LamaPattern createSexpConsPattern(LamaPattern leftElem, LamaPattern rightElem) {
return new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{leftElem, rightElem});
}
public LamaPattern createArrayPattern(LamaPattern[] elems) {
return new LamaArrayPattern(elems);
public LamaPattern createSexpPattern(Token tag, List<LamaPattern> elems) {
return new LamaSexpPattern(LamaStrings.fromJavaString(tag.getText()), elems.toArray(new LamaPattern[0]));
}
public LamaPattern createArrayPattern(List<LamaPattern> elems) {
return new LamaArrayPattern(elems.toArray(new LamaPattern[0]));
}
// sexps-pairs with tag 'cons'
public LamaPattern createListSexpPattern(LamaPattern[] elems) {
public LamaPattern createListSexpPattern(List<LamaPattern> elems) {
LamaPattern result = new LamaConstPattern(0);
for (int i = elems.length - 1; i >= 0; --i) {
result = new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{elems[i], result});
for (int i = elems.size() - 1; i >= 0; --i) {
result = new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{elems.get(i), result});
}
return result;
}
@ -473,6 +575,10 @@ public class LamaNodeFactory {
return new LamaNamedPattern(frameSlot, pattern);
}
public LamaPattern createValueConstPattern(Token token, long value) {
return new LamaConstPattern(value);
}
public LamaPattern createConstPattern(Token token) {
return new LamaConstPattern(Long.parseLong(token.getText()));
}
@ -547,9 +653,12 @@ public class LamaNodeFactory {
// ---
public LamaExpressionNode getRootExpr() {
// TODO
return null;
public void setRootExpr(LamaExpressionNode expr) {
this.rootExpr = expr;
}
public LamaRootNode getRootExpr() {
return new LamaRootNode(language, this.rootExpr);
}