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.Optional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.source.Source;
import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleString;
import org.programsnail.truffle_lama.LamaLanguage; import org.programsnail.truffle_lama.LamaLanguage;
import org.programsnail.truffle_lama.nodes.LamaExpressionNode; import org.programsnail.truffle_lama.nodes.LamaExpressionNode;
import org.programsnail.truffle_lama.nodes.LamaRootNode;
import org.programsnail.truffle_lama.nodes.pattern.LamaPattern;
} }
@lexer::header @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)); 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())); LamaLexer lexer = new LamaLexer(CharStreams.fromString(source.getCharacters().toString()));
LamaParser parser = new LamaParser(new CommonTokenStream(lexer)); LamaParser parser = new LamaParser(new CommonTokenStream(lexer));
lexer.removeErrorListeners(); lexer.removeErrorListeners();
@ -113,26 +114,28 @@ public static LamaExpressionNode parseLama(LamaLanguage language, Source source)
lama returns [LamaExpressionNode result]: lama returns [LamaExpressionNode result]:
/* (import_expression)* */ /* (import_expression)* */
scope_expression { $result = $scope_expression.result; } scope_expression[false] { $result = $scope_expression.result; factory.setRootExpr($result); }
EOF; EOF;
//import_expression : 'import' UIDENT ';'; //import_expression : 'import' UIDENT ';';
scope_expression returns [LamaExpressionNode result]: scope_expression[boolean do_scope] returns [LamaExpressionNode result]
definition { $result = $expression.result; } : { if (do_scope) { factory.enterScope(); } }
(definition { $result = $expression.result; }
( (
definition { $result = factory.createSeqNode($result, $expression.result); } definition { $result = factory.createSeqNode($result, $expression.result); }
)* ( )* (
expression { $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]: definition returns [LamaExpressionNode result]:
variable_definition { $result = $variable_definition.result; } variable_definition { $result = $variable_definition.result; }
| function_definition { $result = $function_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[is_public] { $result = $variable_definition_sequence.result; }
; ;
variable_definition_sequence[boolean is_public] returns [LamaExpressionNode 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] variable_definition_item returns [Token name, LamaExpressionNode expr]
: { $expr = Optional.empty(); } : { $expr = null; }
LIDENT { $name = $LIDENT; } LIDENT { $name = $LIDENT; }
('=' ('='
basic_expression { $expr = Optional.of($basic_expression.result); } basic_expression { $expr = $basic_expression.result; }
)?; )?;
function_definition returns [LamaExpressionNode result] // TODO: scopes function_definition returns [LamaExpressionNode result]
: { boolean is_public = false; } : {
boolean is_public = false;
List<Token> args = new ArrayList<Token>();
factory.enterScope(LamaNodeFactory.LexicalScope.Kind.FUNCTION);
}
( (
'public' { is_public = true; } 'public' { is_public = true; }
)? 'fun' LIDENT '(' (function_arguments)? ')' function_body )? 'fun' LIDENT '(' (
{ $result = factory.defineFunction($LIDENT, $function_arguments.args, $function_body.result); } 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] function_arguments returns [List<Token> args]
: { $args = new ArrayList<TruffleString>(); } : { $args = new ArrayList<Token>(); }
LIDENT { $args.addLast($LIDENT); } LIDENT { $args.addLast($LIDENT); }
(',' (','
LIDENT { $args.addLast($LIDENT); } LIDENT { $args.addLast($LIDENT); }
)*; )*;
function_body returns [LamaExpressionNode result]: 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; } basic_expression { $result = $basic_expression.result; }
(';' (';'
expression { $result = factory.createSeqNode($result, $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; }; basic_expression returns [LamaExpressionNode result]: binary_expression { $result = $binary_expression.result; };
binary_expression returns [LamaExpressionNode result]: binary_expression returns [LamaExpressionNode result]:
postfix_expression { $result = $postfix_expression.result; } postfix_expression { $result = $postfix_expression.result; }
( (
any_infix any_infix
postfix_expression { $result = factory.createBinopNode($any_infix.result, $result, $postfix_expression.result); } 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] postfix_expression returns [LamaExpressionNode result]
: { boolean with_minus = false; } : { boolean with_minus = false; }
( (
@ -202,14 +215,24 @@ postfix_expression returns [LamaExpressionNode result]
( (
postfix { postfix {
if ($postfix.access_index.isPresent()) { 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 { } else {
$result = factory.createCallNode($result, $postfix.args); $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] 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); } 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 DECIMAL_LITERAL { $result = factory.createConstNode($DECIMAL_LITERAL); } // minus - inside decimal literal definition
| STRING_LITERAL { $result = factory.createStringNode($STRING_LITERAL); } | STRING_LITERAL { $result = factory.createStringNode($STRING_LITERAL); }
| CHAR_LITERAL { $result = factory.createCharConstNode($CHAR_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='true' { $result = factory.createValueConstNode($tok, 1); }
| tok='false' { $result = factory.createValueConstNode($tok, 0); } | tok='false' { $result = factory.createValueConstNode($tok, 0); }
| 'infix' any_infix { $result = factory.createRefNode($any_infix.result); } | 'infix' any_infix { $result = factory.createValueNode($any_infix.result); }
| 'fun' '(' function_arguments ')' function_body | tok='fun' '('
{ $result = factory.createClosureNode($function_arguments.args, $function_body.result); } // TODO: scopes {
| 'skip' { $result = factory.createSkipNode(); } List<Token> args = new ArrayList<Token>();
| '(' scope_expression ')' { $result = $scope_expression.result; } // add some scope for correct attribution ?? 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; } | list_expression { $result = $list_expression.result; }
| array_expression { $result = $array_expression.result; } | array_expression { $result = $array_expression.result; }
| s_expression { $result = $s_expression.result; } | s_expression { $result = $s_expression.result; }
@ -282,27 +316,31 @@ s_expression returns [LamaExpressionNode result]
if_expression returns [LamaExpressionNode result] if_expression returns [LamaExpressionNode result]
: { LamaExpressionNode do_else = null; } : { LamaExpressionNode do_else = null; }
'if' expression 'then' scope_expression ( 'if' expression 'then' scope_expression[true]
(
else_part { do_else = $else_part.result; } else_part { do_else = $else_part.result; }
)? 'fi' )? 'fi'
{ $result = factory.createIfNode($expression.result, $scope_expression.result, do_else); } { $result = factory.createIfNode($expression.result, $scope_expression.result, do_else); }
; ;
else_part returns [LamaExpressionNode result]: 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; } else_part { do_else = $else_part.result; }
)? { $result = factory.createIfNode($expression.result, $scope_expression.result, do_else); } )? { $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); }; { $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); }; { $result = factory.createDoWhileNode($expression.result, $scope_expression.result); };
for_expression returns [LamaExpressionNode result]: for_expression returns [LamaExpressionNode result]:
'for' init=scope_expression ',' cond=expression ',' inc=expression 'do' expr=scope_expression 'od' 'for' { factory.enterScope(); }
// TODO: add scope, etc. 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))); } {
$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; } cons_pattern { $result = $cons_pattern.result; }
| simple_pattern { $result = $simple_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]: simple_pattern returns [LamaPattern result]:
wildcard_pattern { $result = $wildcard_pattern.result; } wildcard_pattern { $result = $wildcard_pattern.result; }
| s_expr_pattern { $result = $s_expr_pattern.result; } | s_expr_pattern { $result = $s_expr_pattern.result; }
@ -322,16 +360,16 @@ simple_pattern returns [LamaPattern result]:
('@' ('@'
pattern { pat = $pattern.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; } | { boolean is_negative = false; }
( (
MINUS { is_negative = true; } MINUS { is_negative = true; }
)? )?
DECIMAL_LITERAL { $result = is_negative ? factory.createNegativeConstPattern($DECIMAL_LITERAL) : factory.createConstPattern($DECIMAL_LITERAL); } DECIMAL_LITERAL { $result = is_negative ? factory.createNegativeConstPattern($DECIMAL_LITERAL) : factory.createConstPattern($DECIMAL_LITERAL); }
| STRING_LITERAL { $result = factory.createStringPattern(LamaStrings.convertStringLiteral($STRING_LITERAL)); } | STRING_LITERAL { $result = factory.createStringPattern($STRING_LITERAL); }
| CHAR_LITERAL { $result = factory.createConstPattern(LamaStrings.convertCharLiteral($CHAR_LITERAL)); } | CHAR_LITERAL { $result = factory.createConstPattern($CHAR_LITERAL); }
| 'true' { $result = factory.createConstPattern(1); } | tok='true' { $result = factory.createValueConstPattern($tok, 1); }
| 'false' { $result = factory.createConstPattern(0); } | tok='false' { $result = factory.createValueConstPattern($tok, 0); }
| '#' 'box' { $result = factory.createBoxedPattern(); } | '#' 'box' { $result = factory.createBoxedPattern(); }
| '#' 'val' { $result = factory.createUnBoxedPattern(); } | '#' 'val' { $result = factory.createUnBoxedPattern(); }
| '#' 'str' { $result = factory.createStringTagPattern(); } | '#' 'str' { $result = factory.createStringTagPattern(); }
@ -368,7 +406,7 @@ list_pattern returns [LamaPattern result]
'{' ( '{' (
pattern { elems.addLast($pattern.result); } pattern { elems.addLast($pattern.result); }
(',' (','
pattern { elems.addLast($pattern.result); } //FIXME: wrong order pattern { elems.addLast($pattern.result); }
)*)? )*)?
'}' '}'
{ $result = factory.createListSexpPattern(elems); } { $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' 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] 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 { $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; } 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; } INFIX { $result = $INFIX; }
| MINUS { $result = $MINUS; } | 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; 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.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.source.Source; 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.LamaLanguage;
import org.programsnail.truffle_lama.LamaStrings; import org.programsnail.truffle_lama.LamaStrings;
import org.programsnail.truffle_lama.nodes.LamaExpressionNode; 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.LamaCaseNode;
import org.programsnail.truffle_lama.nodes.controlflow.LamaDoWhileNode; import org.programsnail.truffle_lama.nodes.controlflow.LamaDoWhileNode;
import org.programsnail.truffle_lama.nodes.controlflow.LamaIfNode; import org.programsnail.truffle_lama.nodes.controlflow.LamaIfNode;
@ -132,7 +132,7 @@ public class LamaNodeFactory {
// --- // ---
public boolean isGlobal() { public boolean isGlobal() {
return outer == null; return top == null;
} }
public boolean isFramed() { public boolean isFramed() {
@ -261,31 +261,102 @@ public class LamaNodeFactory {
private final Source source; private final Source source;
private final TruffleString sourceString; private final TruffleString sourceString;
/* State while parsing an expr. */
private LexicalScope lexicalScope; private LexicalScope lexicalScope;
private final LamaLanguage language; 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) { public LamaNodeFactory(LamaLanguage language, Source source) {
this.language = language; this.language = language;
this.source = source; this.source = source;
this.sourceString = LamaStrings.fromJavaString(source.getCharacters().toString()); 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) { public void enterScope(LexicalScope.Kind kind) {
lexicalScope = new LexicalScope(lexicalScope, kind); lexicalScope = new LexicalScope(lexicalScope, kind);
} }
public void exitScope() { public void exitScope() {
// TODO: save vars to clear them & create corresponding scope node ??
lexicalScope = lexicalScope.getOuter(); 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 // TODO: add to parser
public void AddFunctionArguments(Token[] args) { public void addFunctionArguments(List<Token> args) {
for (Token arg : args) { for (Token arg : args) {
lexicalScope.addArgument(arg.getText()); lexicalScope.addArgument(arg.getText());
} }
@ -327,7 +398,7 @@ public class LamaNodeFactory {
public LamaExpressionNode createVarNode(Token token) { public LamaExpressionNode createVarNode(Token token) {
String name = token.getText(); 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*/ return addSrcFromToken(lexicalScope.isGlobal() /*global scope*/
? new LamaGlobalVarNode(name) ? new LamaGlobalVarNode(name)
: new LamaLocalVarNode(slot), token); : new LamaLocalVarNode(slot), token);
@ -340,6 +411,10 @@ public class LamaNodeFactory {
// TODO: fix assignment in parser // TODO: fix assignment in parser
public LamaExpressionNode createAssignVarNode(Token token, LamaExpressionNode value) { public LamaExpressionNode createAssignVarNode(Token token, LamaExpressionNode value) {
var definition = createVarNode(token); var definition = createVarNode(token);
if (value == null) {
return definition;
}
var reference = createRefNode(token); var reference = createRefNode(token);
var assignment = createAssignNode(reference, value); var assignment = createAssignNode(reference, value);
return createSeqNode(definition, assignment); return createSeqNode(definition, assignment);
@ -353,11 +428,14 @@ public class LamaNodeFactory {
public LamaExpressionNode createAnyBinopNode(Token opToken, LamaExpressionNode left, LamaExpressionNode right) { public LamaExpressionNode createAnyBinopNode(Token opToken, LamaExpressionNode left, LamaExpressionNode right) {
String op = opToken.getText(); String op = opToken.getText();
return switch (op) { return switch (op) {
// case ":" -> // TODO: cons
case ":=" -> createAssignNode(left, right); case ":=" -> createAssignNode(left, right);
case "+", "-", "/", "%", case "+", "-", "/", "%",
"<", "<=", ">", ">=", "==", "!=", "<", "<=", ">", ">=", "==", "!=",
"&&", "!!" -> createBinopNode(opToken, left, right); "&&", "!!" -> 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); 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) { public LamaExpressionNode createElemRefOrValueNode(LamaExpressionNode array, LamaExpressionNode index, boolean doUnref) {
return addUnref(createElemRefNode(array, index), doUnref); return addUnref(createElemRefNode(array, index), doUnref);
} }
@ -374,8 +457,16 @@ public class LamaNodeFactory {
return addSrcFromNodes(LamaElemRefNodeGen.create(array, index), array, index); return addSrcFromNodes(LamaElemRefNodeGen.create(array, index), array, index);
} }
public LamaExpressionNode createCallNode(LamaExpressionNode func, LamaExpressionNode[] args) { public LamaExpressionNode createCallNode(LamaExpressionNode func, List<LamaExpressionNode> args) {
return addSrcFromNodes(new LamaCallNode(func, args), func, args.length > 0 ? args[args.length - 1] : func); 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) { public LamaExpressionNode createRefOrValueNode(Token token, boolean doUnref) {
@ -407,27 +498,28 @@ public class LamaNodeFactory {
return addSrcFromToken(new LamaSkipNode(), token); return addSrcFromToken(new LamaSkipNode(), token);
} }
public LamaExpressionNode createArrayNode(LamaExpressionNode[] elems) { public LamaExpressionNode createArrayNode(List<LamaExpressionNode> elems) {
LamaExpressionNode result = new LamaArrayNode(elems); LamaExpressionNode[] elemsArray = elems.toArray(new LamaExpressionNode[0]);
return elems.length > 0 ? addSrcFromNodes(result, elems[0], elems[elems.length - 1]) : result; LamaExpressionNode result = new LamaArrayNode(elemsArray);
return elems.isEmpty() ? result : addSrcFromNodes(result, elems.getFirst(), elems.getLast());
} }
// sexps-pairs with tag 'cons' // sexps-pairs with tag 'cons'
public LamaExpressionNode createListSexpNode(LamaExpressionNode[] elems) { public LamaExpressionNode createListSexpNode(List<LamaExpressionNode> elems) {
LamaExpressionNode result = new LamaConstNode(0); LamaExpressionNode result = new LamaConstNode(0);
for (int i = elems.length - 1; i >= 0; --i) { for (int i = elems.size() - 1; i >= 0; --i) {
result = new LamaSexpNode(LamaStrings.fromJavaString("cons"), new LamaExpressionNode[]{elems[i], result}); 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) { public LamaExpressionNode createSexpNode(Token tag, List<LamaExpressionNode> elems) {
LamaExpressionNode result = new LamaSexpNode(LamaStrings.fromJavaString(tag.getText()), elems); LamaExpressionNode result = new LamaSexpNode(LamaStrings.fromJavaString(tag.getText()), elems.toArray(new LamaExpressionNode[0]));
return elems.length > 0 ? addSrcFromNodes(result, elems[0]/*TODO: use tag instead*/, elems[elems.length - 1]) : addSrcFromToken(result, tag); return elems.isEmpty() ? addSrcFromToken(result, tag) : addSrcFromTokenAndNode(result, tag, elems.getLast());
} }
public LamaExpressionNode createIfNode(LamaExpressionNode condition, LamaExpressionNode doThen, LamaExpressionNode doElse) { 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) { public LamaExpressionNode createWhileNode(LamaExpressionNode condition, LamaExpressionNode body) {
@ -438,10 +530,16 @@ public class LamaNodeFactory {
return addSrcFromNodes(new LamaDoWhileNode(condition, body), condition, body); return addSrcFromNodes(new LamaDoWhileNode(condition, body), condition, body);
} }
public LamaExpressionNode createCaseNode(LamaExpressionNode value, LamaPattern[] patterns, LamaExpressionNode[] exprs) { public LamaExpressionNode createCaseNode(LamaExpressionNode value, List<LamaPattern> patterns, List<LamaExpressionNode> exprs) {
assert patterns.length == exprs.length; assert patterns.size() == exprs.size();
assert patterns.length > 0; assert !patterns.isEmpty();
return addSrcFromNodes(new LamaCaseNode(value, patterns, exprs), value, exprs[exprs.length - 1]); 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(); return new LamaWildcardPattern();
} }
public LamaPattern createSexpPattern(Token tag, LamaPattern[] elems) { public LamaPattern createSexpConsPattern(LamaPattern leftElem, LamaPattern rightElem) {
return new LamaSexpPattern(LamaStrings.fromJavaString(tag.getText()), elems); return new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{leftElem, rightElem});
} }
public LamaPattern createArrayPattern(LamaPattern[] elems) { public LamaPattern createSexpPattern(Token tag, List<LamaPattern> elems) {
return new LamaArrayPattern(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' // sexps-pairs with tag 'cons'
public LamaPattern createListSexpPattern(LamaPattern[] elems) { public LamaPattern createListSexpPattern(List<LamaPattern> elems) {
LamaPattern result = new LamaConstPattern(0); LamaPattern result = new LamaConstPattern(0);
for (int i = elems.length - 1; i >= 0; --i) { for (int i = elems.size() - 1; i >= 0; --i) {
result = new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{elems[i], result}); result = new LamaSexpPattern(LamaStrings.fromJavaString("cons"), new LamaPattern[]{elems.get(i), result});
} }
return result; return result;
} }
@ -473,6 +575,10 @@ public class LamaNodeFactory {
return new LamaNamedPattern(frameSlot, pattern); return new LamaNamedPattern(frameSlot, pattern);
} }
public LamaPattern createValueConstPattern(Token token, long value) {
return new LamaConstPattern(value);
}
public LamaPattern createConstPattern(Token token) { public LamaPattern createConstPattern(Token token) {
return new LamaConstPattern(Long.parseLong(token.getText())); return new LamaConstPattern(Long.parseLong(token.getText()));
} }
@ -547,9 +653,12 @@ public class LamaNodeFactory {
// --- // ---
public LamaExpressionNode getRootExpr() { public void setRootExpr(LamaExpressionNode expr) {
// TODO this.rootExpr = expr;
return null; }
public LamaRootNode getRootExpr() {
return new LamaRootNode(language, this.rootExpr);
} }