2024-02-21 13:45:54 +01:00
using System ;
using System.Collections.Generic ;
2024-02-21 15:05:06 +01:00
using System.Text.Json.Serialization ;
2024-02-21 13:45:54 +01:00
2024-02-01 02:20:22 +01:00
namespace luaaaaah ;
class Parser
{
public class ChunkNode ( BlockNode block , CodeRegion startRegion , CodeRegion endRegion )
{
public BlockNode block = block ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class BlockNode ( List < StatNode > stats , CodeRegion startRegion , CodeRegion endRegion )
{
public List < StatNode > stats = stats ;
public RetstatNode ? retstat ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Semicolon), typeDiscriminator: "st Semicolon")]
[JsonDerivedType(typeof(Assignment), typeDiscriminator: "st Assignment")]
[JsonDerivedType(typeof(Functioncall), typeDiscriminator: "st Functioncall")]
[JsonDerivedType(typeof(Label), typeDiscriminator: "st Label")]
[JsonDerivedType(typeof(Break), typeDiscriminator: "st Break")]
[JsonDerivedType(typeof(Goto), typeDiscriminator: "st Goto")]
[JsonDerivedType(typeof(Do), typeDiscriminator: "st Do")]
[JsonDerivedType(typeof(While), typeDiscriminator: "st While")]
[JsonDerivedType(typeof(Repeat), typeDiscriminator: "st Repeat")]
[JsonDerivedType(typeof(If), typeDiscriminator: "st If")]
[JsonDerivedType(typeof(ForNumerical), typeDiscriminator: "st ForNum")]
[JsonDerivedType(typeof(ForGeneric), typeDiscriminator: "st ForGen")]
[JsonDerivedType(typeof(Function), typeDiscriminator: "st Function")]
[JsonDerivedType(typeof(LocalFunction), typeDiscriminator: "st LocalFunction")]
[JsonDerivedType(typeof(Local), typeDiscriminator: "st Local")]
2024-02-01 02:20:22 +01:00
public abstract class StatNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Semicolon ( CodeRegion region ) : StatNode ( region , region ) { }
public class Assignment ( AssignmentNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public AssignmentNode node = node ;
}
public class Functioncall ( FunctioncallNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public FunctioncallNode node = node ;
}
public class Label ( string label , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public string label = label ;
}
public class Break ( CodeRegion region ) : StatNode ( region , region ) { }
public class Goto ( string label , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public string label = label ;
}
public class Do ( BlockNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public BlockNode node = node ;
}
public class While ( WhileNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public WhileNode node = node ;
}
public class Repeat ( RepeatNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public RepeatNode node = node ;
}
public class If ( IfNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public IfNode node = node ;
}
public class ForNumerical ( ForNumericalNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public ForNumericalNode node = node ;
}
public class ForGeneric ( ForGenericNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public ForGenericNode node = node ;
}
public class Function ( FunctionNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public FunctionNode node = node ;
}
public class LocalFunction ( LocalFunctionNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public LocalFunctionNode node = node ;
}
public class Local ( LocalNode node , CodeRegion startRegion , CodeRegion endRegion ) : StatNode ( startRegion , endRegion )
{
public LocalNode node = node ;
}
}
2024-02-21 13:48:02 +01:00
public class RetstatNode ( ExplistNode ? values , CodeRegion startRegion , CodeRegion endRegion )
2024-02-01 02:20:22 +01:00
{
2024-02-21 13:48:02 +01:00
public ExplistNode ? values = values ;
2024-02-01 02:20:22 +01:00
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class AssignmentNode ( VarlistNode lhs , ExplistNode rhs , CodeRegion startRegion , CodeRegion endRegion )
{
public VarlistNode lhs = lhs ;
public ExplistNode rhs = rhs ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class FunctioncallNode ( SuffixexpNode function , string? objectArg , ArgsNode args , CodeRegion startRegion , CodeRegion endRegion )
{
public SuffixexpNode function = function ;
public string? objectArg = objectArg ;
public ArgsNode args = args ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class WhileNode ( ExpNode condition , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode condition = condition ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class RepeatNode ( ExpNode condition , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode condition = condition ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class IfNode ( ExpNode condition , BlockNode body , List < ElseifNode > elseifs , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode condition = condition ;
public BlockNode body = body ;
public List < ElseifNode > elseifs = elseifs ;
public BlockNode ? else_ ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class ForNumericalNode ( string variable , ExpNode start , ExpNode end , ExpNode ? change , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public string variable = variable ;
public ExpNode start = start ;
public ExpNode end = end ;
public ExpNode ? change = change ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class ForGenericNode ( List < string > vars , ExplistNode exps , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public List < string > vars = vars ;
public ExplistNode exps = exps ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class FunctionNode ( FuncnameNode name , FuncbodyNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public FuncnameNode name = name ;
public FuncbodyNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class LocalFunctionNode ( string name , FuncbodyNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public string name = name ;
public FuncbodyNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class LocalNode ( AttnamelistNode attnames , ExplistNode ? values , CodeRegion startRegion , CodeRegion endRegion )
{
public AttnamelistNode attnames = attnames ;
public ExplistNode ? values = values ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class ExplistNode ( List < ExpNode > exps , CodeRegion startRegion , CodeRegion endRegion )
{
public List < ExpNode > exps = exps ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class VarlistNode ( List < VarNode > vars , CodeRegion startRegion , CodeRegion endRegion )
{
public List < VarNode > vars = vars ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Normal), typeDiscriminator: "s Normal")]
[JsonDerivedType(typeof(Functioncall), typeDiscriminator: "s Functioncall")]
2024-02-01 02:20:22 +01:00
public abstract class SuffixexpNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Normal ( NormalSuffixNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpNode ( startRegion , endRegion )
{
public NormalSuffixNode node = node ;
}
public class Functioncall ( FunctioncallNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpNode ( startRegion , endRegion )
{
public FunctioncallNode node = node ;
}
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Bracketed), typeDiscriminator: "a Bracketed")]
[JsonDerivedType(typeof(Tableconstructor), typeDiscriminator: "a Tableconstructor")]
[JsonDerivedType(typeof(Literal), typeDiscriminator: "a Literal")]
2024-02-01 02:20:22 +01:00
public abstract class ArgsNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Bracketed ( ExplistNode ? node , CodeRegion startRegion , CodeRegion endRegion ) : ArgsNode ( startRegion , endRegion )
{
public ExplistNode ? node = node ;
}
public class Tableconstructor ( TableconstructorNode node , CodeRegion startRegion , CodeRegion endRegion ) : ArgsNode ( startRegion , endRegion )
{
public TableconstructorNode node = node ;
}
public class Literal ( string name , CodeRegion startRegion , CodeRegion endRegion ) : ArgsNode ( startRegion , endRegion )
{
public string name = name ;
}
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Nil), typeDiscriminator: "e Nil")]
[JsonDerivedType(typeof(False), typeDiscriminator: "e True")]
[JsonDerivedType(typeof(True), typeDiscriminator: "e False")]
[JsonDerivedType(typeof(Numeral), typeDiscriminator: "e Numeral")]
[JsonDerivedType(typeof(LiteralString), typeDiscriminator: "e Literal")]
[JsonDerivedType(typeof(Varargs), typeDiscriminator: "e Varargs")]
[JsonDerivedType(typeof(Functiondef), typeDiscriminator: "e Functiondef")]
[JsonDerivedType(typeof(Suffixexp), typeDiscriminator: "e Suffixexp")]
[JsonDerivedType(typeof(Tableconstructor), typeDiscriminator: "e Tableconstructor")]
[JsonDerivedType(typeof(Unop), typeDiscriminator: "e Unop")]
[JsonDerivedType(typeof(Binop), typeDiscriminator: "e Binop")]
2024-02-01 02:20:22 +01:00
public abstract class ExpNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Nil ( CodeRegion region ) : ExpNode ( region , region ) { }
public class False ( CodeRegion region ) : ExpNode ( region , region ) { }
public class True ( CodeRegion region ) : ExpNode ( region , region ) { }
2024-02-21 13:47:38 +01:00
public class Numeral ( INumeral value , CodeRegion region ) : ExpNode ( region , region )
2024-02-01 02:20:22 +01:00
{
public INumeral value = value ;
}
2024-02-21 13:47:38 +01:00
public class LiteralString ( string value , CodeRegion region ) : ExpNode ( region , region )
2024-02-01 02:20:22 +01:00
{
public string value = value ;
}
public class Varargs ( CodeRegion region ) : ExpNode ( region , region ) { }
public class Functiondef ( FuncbodyNode node , CodeRegion startRegion , CodeRegion endRegion ) : ExpNode ( startRegion , endRegion )
{
public FuncbodyNode node = node ;
}
public class Suffixexp ( SuffixexpNode node , CodeRegion startRegion , CodeRegion endRegion ) : ExpNode ( startRegion , endRegion )
{
public SuffixexpNode node = node ;
}
public class Tableconstructor ( TableconstructorNode node , CodeRegion startRegion , CodeRegion endRegion ) : ExpNode ( startRegion , endRegion )
{
public TableconstructorNode node = node ;
}
public class Unop ( UnopNode node , CodeRegion startRegion , CodeRegion endRegion ) : ExpNode ( startRegion , endRegion )
{
public UnopNode node = node ;
}
public class Binop ( BinopNode node , CodeRegion startRegion , CodeRegion endRegion ) : ExpNode ( startRegion , endRegion )
{
public BinopNode node = node ;
}
}
public class ElseifNode ( ExpNode condition , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode condition = condition ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class FuncnameNode ( string name , List < string > dottedNames , string? firstArg , CodeRegion startRegion , CodeRegion endRegion )
{
public string name = name ;
public List < string > dottedNames = dottedNames ;
public string? firstArg = firstArg ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class FuncbodyNode ( ParlistNode ? pars , BlockNode body , CodeRegion startRegion , CodeRegion endRegion )
{
public ParlistNode ? pars = pars ;
public BlockNode body = body ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class AttnamelistNode ( List < AttnameNode > attnames , CodeRegion startRegion , CodeRegion endRegion )
{
public List < AttnameNode > attnames = attnames ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Name), typeDiscriminator: "v Name")]
[JsonDerivedType(typeof(Indexed), typeDiscriminator: "v Indexed")]
[JsonDerivedType(typeof(Member), typeDiscriminator: "v Member")]
2024-02-01 02:20:22 +01:00
public abstract class VarNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Name ( string name , CodeRegion startRegion , CodeRegion endRegion ) : VarNode ( startRegion , endRegion )
{
public string name = name ;
}
public class Indexed ( IndexedVarNode node , CodeRegion startRegion , CodeRegion endRegion ) : VarNode ( startRegion , endRegion )
{
public IndexedVarNode node = node ;
}
public class Member ( MemberVarNode node , CodeRegion startRegion , CodeRegion endRegion ) : VarNode ( startRegion , endRegion )
{
public MemberVarNode node = node ;
}
}
public class NormalSuffixNode ( SuffixexpFirstPart firstPart , List < SuffixexpSuffix > suffixes , CodeRegion startRegion , CodeRegion endRegion )
{
public SuffixexpFirstPart firstPart = firstPart ;
public List < SuffixexpSuffix > suffixes = suffixes ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class TableconstructorNode ( FieldlistNode ? exps , CodeRegion startRegion , CodeRegion endRegion )
{
public FieldlistNode ? exps = exps ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class UnopNode ( UnopType type , ExpNode exp , CodeRegion startRegion , CodeRegion endRegion )
{
public UnopType type = type ;
public ExpNode exp = exp ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public enum UnopType
{
Minus , LogicalNot , Length , BinaryNot ,
}
public class BinopNode ( ExpNode lhs , BinopType type , ExpNode rhs , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode lhs = lhs ;
public BinopType type = type ;
public ExpNode rhs = rhs ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public enum BinopType
{
LogicalOr ,
LogicalAnd ,
Lt , Gt , LtEquals , GtEquals , NotEquals , Equals ,
BinaryOr ,
BinaryNot ,
BinaryAnd ,
Shl , Shr ,
Concat ,
Add , Sub ,
Mul , Div , IntDiv , Mod ,
Exp ,
}
public class ParlistNode ( List < string > names , bool hasVarargs , CodeRegion startRegion , CodeRegion endRegion )
{
public List < string > names = names ;
public bool hasVarargs = hasVarargs ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class AttnameNode ( string name , string? attribute , CodeRegion startRegion , CodeRegion endRegion )
{
public string name = name ;
public string? attribute = attribute ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class IndexedVarNode ( SuffixexpNode value , ExpNode index , CodeRegion startRegion , CodeRegion endRegion )
{
public SuffixexpNode value = value ;
public ExpNode index = index ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class MemberVarNode ( SuffixexpNode value , string name , CodeRegion startRegion , CodeRegion endRegion )
{
public SuffixexpNode value = value ;
public string name = name ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Name), typeDiscriminator: "sfp Name")]
[JsonDerivedType(typeof(BracketedExp), typeDiscriminator: "sfp BracketedExp")]
2024-02-01 02:20:22 +01:00
public abstract class SuffixexpFirstPart ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class Name ( string name , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpFirstPart ( startRegion , endRegion )
{
public string name = name ;
}
public class BracketedExp ( ExpNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpFirstPart ( startRegion , endRegion )
{
public ExpNode node = node ;
}
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(Dot))]
[JsonDerivedType(typeof(Indexed))]
[JsonDerivedType(typeof(Args))]
[JsonDerivedType(typeof(ArgsFirstArg))]
2024-02-01 02:20:22 +01:00
public abstract class SuffixexpSuffix ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
2024-02-21 13:47:02 +01:00
public class Dot ( string name , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpSuffix ( startRegion , endRegion )
2024-02-01 02:20:22 +01:00
{
public string name = name ;
}
2024-02-21 13:47:02 +01:00
public class Indexed ( ExpNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpSuffix ( startRegion , endRegion )
2024-02-01 02:20:22 +01:00
{
public ExpNode node = node ;
}
2024-02-21 13:47:02 +01:00
public class Args ( ArgsNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpSuffix ( startRegion , endRegion )
2024-02-01 02:20:22 +01:00
{
public ArgsNode node = node ;
}
2024-02-21 13:47:02 +01:00
public class ArgsFirstArg ( ArgsFirstArgNode node , CodeRegion startRegion , CodeRegion endRegion ) : SuffixexpSuffix ( startRegion , endRegion )
2024-02-01 02:20:22 +01:00
{
public ArgsFirstArgNode node = node ;
}
}
public class FieldlistNode ( List < FieldNode > exps , CodeRegion startRegion , CodeRegion endRegion )
{
public List < FieldNode > exps = exps ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class ArgsFirstArgNode ( string name , ArgsNode rest , CodeRegion startRegion , CodeRegion endRegion )
{
public string name = name ;
public ArgsNode rest = rest ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
2024-02-21 15:05:06 +01:00
[JsonDerivedType(typeof(IndexedAssignment))]
[JsonDerivedType(typeof(Assignment))]
[JsonDerivedType(typeof(Exp))]
2024-02-01 02:20:22 +01:00
public abstract class FieldNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
public class IndexedAssignment ( IndexedAssignmentNode node , CodeRegion startRegion , CodeRegion endRegion ) : FieldNode ( startRegion , endRegion )
{
public IndexedAssignmentNode node = node ;
}
public class Assignment ( FieldAssignmentNode node , CodeRegion startRegion , CodeRegion endRegion ) : FieldNode ( startRegion , endRegion )
{
public FieldAssignmentNode node = node ;
}
public class Exp ( ExpNode node , CodeRegion startRegion , CodeRegion endRegion ) : FieldNode ( startRegion , endRegion )
{
public ExpNode node = node ;
}
}
public class IndexedAssignmentNode ( ExpNode index , ExpNode rhs , CodeRegion startRegion , CodeRegion endRegion )
{
public ExpNode index = index ;
public ExpNode rhs = rhs ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public class FieldAssignmentNode ( string lhs , ExpNode rhs , CodeRegion startRegion , CodeRegion endRegion )
{
public string lhs = lhs ;
public ExpNode rhs = rhs ;
public CodeRegion startRegion = startRegion , endRegion = endRegion ;
}
public int index ;
public ChunkNode Parse ( Token [ ] tokens )
{
return ParseChunk ( tokens ) ;
}
public ChunkNode ParseChunk ( Token [ ] tokens )
{
BlockNode body = ParseBlock ( tokens ) ;
return new ChunkNode ( block : body , startRegion : body . startRegion , endRegion : body . endRegion ) ;
}
public BlockNode ParseBlock ( Token [ ] tokens )
{
CodeRegion startRegion = tokens [ index ] . region ;
List < StatNode > stats = [ ] ;
while ( index < tokens . Length & &
tokens [ index ] . type ! = TokenType . Return & &
tokens [ index ] . type ! = TokenType . End & &
tokens [ index ] . type ! = TokenType . Elseif & &
2024-02-21 15:07:37 +01:00
tokens [ index ] . type ! = TokenType . Else & &
tokens [ index ] . type ! = TokenType . Until )
2024-02-01 02:20:22 +01:00
{
stats . Add ( ParseStat ( tokens ) ) ;
}
2024-02-21 13:48:43 +01:00
BlockNode ret = new ( stats : stats , startRegion : startRegion , endRegion : ( stats . Count = = 0 ) ? startRegion : stats [ ^ 1 ] . endRegion ) ;
2024-02-01 02:20:22 +01:00
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Return )
{
ret . retstat = ParseRetstat ( tokens ) ;
}
return ret ;
}
public StatNode ParseStat ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
switch ( tokens [ index ] . type )
{
case TokenType . Semicolon :
{
index + = 1 ;
return new StatNode . Semicolon ( startRegion ) ;
}
case TokenType . Break :
{
index + = 1 ;
return new StatNode . Break ( startRegion ) ;
}
case TokenType . Goto :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name for goto at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name for goto, got {tokens[index].type}" ) ;
}
StatNode . Goto ret = new ( label : ( ( Token . StringData ) tokens [ index ] . data ! ) . data , startRegion : startRegion , endRegion : tokens [ index ] . region ) ;
index + = 1 ;
return ret ;
}
case TokenType . Do :
{
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected end for `do` at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close `do` at {startRegion}, got {tokens[index].type}" ) ;
}
StatNode . Do ret = new ( node : body , startRegion : startRegion , endRegion : tokens [ index ] . region ) ;
index + = 1 ;
return ret ;
}
case TokenType . While :
{
index + = 1 ;
ExpNode condition = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `do` after condition of while loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Do )
{
throw new Exception ( $"{tokens[index].region}: Expected `do` after condition of while starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` after body of while loop starting at {startRegion}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . While ( new ( condition : condition , body : body , startRegion : startRegion , endRegion : endRegion ) , startRegion : startRegion , endRegion : endRegion ) ;
}
case TokenType . Repeat :
{
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `until` after body of until loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Until )
{
throw new Exception ( $"{tokens[index].region}: Expected `until` after block of until loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
ExpNode conditon = ParseExp ( tokens ) ;
return new StatNode . Repeat ( new ( condition : conditon , body : body , startRegion : startRegion , endRegion : conditon . endRegion ) , startRegion : startRegion , endRegion : conditon . endRegion ) ;
}
case TokenType . If :
{
index + = 1 ;
ExpNode condition = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `then` after condition of if starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Then )
{
throw new Exception ( $"{tokens[index].region}: Expected `then` after condition of if starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` after body of if starting at {startRegion}" ) ;
}
List < ElseifNode > elseifs = [ ] ;
while ( tokens [ index ] . type = = TokenType . Elseif )
{
CodeRegion elseifStartRegion = tokens [ index ] . region ;
index + = 1 ;
ExpNode elseifCondition = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `then` after condition of elseif starting at {elseifStartRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Then )
{
throw new Exception ( $"{tokens[index].region}: Expected `then` after condition of elseif starting at {elseifStartRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode elseifBody = ParseBlock ( tokens ) ;
elseifs . Add ( new ( condition : elseifCondition , body : elseifBody , startRegion : elseifStartRegion , endRegion : elseifBody . endRegion ) ) ;
}
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` after else-ifs of if starting at {startRegion}" ) ;
}
IfNode ret = new ( condition : condition , body : body , elseifs : elseifs , startRegion : startRegion , endRegion : tokens [ index - 1 ] . region ) ;
2024-02-21 15:08:16 +01:00
if ( tokens [ index ] . type = = TokenType . Else )
2024-02-01 02:20:22 +01:00
{
index + = 1 ;
ret . else_ = ParseBlock ( tokens ) ;
}
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` to close if starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close if starting at {startRegion}, got {tokens[index].type}" ) ;
}
ret . endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . If ( node : ret , startRegion : startRegion , endRegion : ret . endRegion ) ;
}
case TokenType . For :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name after for at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name after for at {startRegion}, got {tokens[index].type}" ) ;
}
string variable = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
switch ( tokens [ index ] . type )
{
case TokenType . Equals :
{
index + = 1 ;
ExpNode start = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `,` after start value of numerical for loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Comma )
{
throw new Exception ( $"{tokens[index].region}: Expected `,` after start value of for loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
ExpNode end = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `do` or `,` after end value of numerical for loop starting at {startRegion}" ) ;
}
ExpNode ? change = null ;
if ( tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
change = ParseExp ( tokens ) ;
}
if ( index > = tokens . Length )
{
string t = ( change = = null ) ? "`do` or `,` after end value" : "`do` after change value" ;
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected {t} of numerical for loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Do )
{
string t = ( change = = null ) ? "`do` or `,` after end value" : "`do` after change value" ;
throw new Exception ( $"{tokens[index].region}: Expected {t} of numerical for loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` to close numerical for loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close numerical for loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . ForNumerical ( new ( variable : variable , start : start , end : end , change : change , body : body , startRegion : startRegion , endRegion : endRegion ) , startRegion : startRegion , endRegion : endRegion ) ;
}
case TokenType . Comma :
{
List < string > names = [ variable ] ;
while ( tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected another name in name list of for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected another name in name list of for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
names . Add ( ( ( Token . StringData ) tokens [ index ] . data ! ) . data ) ;
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `,` or `in` in for-in loop starting at {startRegion}" ) ;
}
}
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `in` after name list of for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . In )
{
throw new Exception ( $"{tokens[index].region}: Expected `in` after name list of for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
ExplistNode exps = ParseExplist ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `do` after exp list of for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Do )
{
throw new Exception ( $"{tokens[index].region}: Expected `do` after exp list of for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` to close for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . ForGeneric ( new ( vars : names , exps : exps , body : body , startRegion : startRegion , endRegion : endRegion ) , startRegion : startRegion , endRegion : endRegion ) ;
}
case TokenType . In :
{
index + = 1 ;
ExplistNode exps = ParseExplist ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `do` after exp list of for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Do )
{
throw new Exception ( $"{tokens[index].region}: Expected `do` after exp list of for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` to close for-in loop starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close for-in loop starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . ForGeneric ( new ( vars : [ variable ] , exps : exps , body : body , startRegion : startRegion , endRegion : endRegion ) , startRegion : startRegion , endRegion : endRegion ) ;
}
default :
{
throw new Exception ( $"{tokens[index].type}: Expected either `=`, `,` or `in` after first name of for loop {startRegion}, got {tokens[index].type}" ) ;
}
}
}
case TokenType . Function :
{
index + = 1 ;
FuncnameNode name = ParseFuncname ( tokens ) ;
FuncbodyNode body = ParseFuncbody ( tokens ) ;
return new StatNode . Function ( new ( name : name , body : body , startRegion : startRegion , endRegion : body . endRegion ) , startRegion : startRegion , endRegion : body . endRegion ) ;
}
case TokenType . Local :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length} after `local` at {startRegion}" ) ;
}
if ( tokens [ index ] . type = = TokenType . Function )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name of local function starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name of local function starting at {startRegion}, got {tokens[index].type}" ) ;
}
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
FuncbodyNode body = ParseFuncbody ( tokens ) ;
return new StatNode . LocalFunction ( new ( name : name , body : body , startRegion : startRegion , endRegion : body . endRegion ) , startRegion : startRegion , endRegion : body . endRegion ) ;
}
else
{
AttnamelistNode attnames = ParseAttnamelist ( tokens ) ;
LocalNode ret = new ( attnames : attnames , values : null , startRegion : startRegion , endRegion : attnames . endRegion ) ;
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Equals )
{
index + = 1 ;
ret . values = ParseExplist ( tokens ) ;
ret . endRegion = ret . values . endRegion ;
}
return new StatNode . Local ( ret , startRegion : startRegion , endRegion : ret . endRegion ) ;
}
}
case TokenType . ColonColon :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name of label starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name of label starting at {startRegion}, got {tokens[index].type}" ) ;
}
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `::` after label name starting at {startRegion}" ) ;
}
2024-02-21 15:08:50 +01:00
if ( tokens [ index ] . type ! = TokenType . ColonColon )
2024-02-01 02:20:22 +01:00
{
throw new Exception ( $"{tokens[index].region}: Expected `::` after label name starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new StatNode . Label ( label : name , startRegion : startRegion , endRegion : endRegion ) ;
}
case TokenType . Name :
case TokenType . RoundOpen :
{
SuffixexpNode suffixExp = ParseSuffixExp ( tokens ) ;
if ( index > = tokens . Length )
{
if ( suffixExp is SuffixexpNode . Normal )
{
throw new Exception ( $"{startRegion}: Expected function call, got normal suffix expression" ) ;
}
if ( suffixExp is SuffixexpNode . Functioncall functioncall )
{
return new StatNode . Functioncall ( node : functioncall . node , startRegion : functioncall . startRegion , endRegion : functioncall . endRegion ) ;
}
}
else
{
switch ( tokens [ index ] . type )
{
case TokenType . Equals :
{
index + = 1 ;
List < VarNode > lhs = [ SuffixExpToVar ( suffixExp ) ] ;
ExplistNode rhs = ParseExplist ( tokens ) ;
return new StatNode . Assignment ( new ( lhs : new ( vars : lhs , startRegion : startRegion , endRegion : suffixExp . endRegion ) , rhs : rhs , startRegion : startRegion , endRegion : rhs . endRegion ) , startRegion : startRegion , endRegion : rhs . endRegion ) ;
}
case TokenType . Comma :
{
List < VarNode > vars = [ SuffixExpToVar ( suffixExp ) ] ;
while ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
vars . Add ( ParseVar ( tokens ) ) ;
}
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `=` for assignment starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Equals )
{
throw new Exception ( $"{tokens[index].region}: Expected `=` for assignment starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
VarlistNode varlistNode = new ( vars : vars , startRegion : startRegion , endRegion : vars [ ^ 1 ] . endRegion ) ;
ExplistNode rhs = ParseExplist ( tokens ) ;
return new StatNode . Assignment ( new ( lhs : varlistNode , rhs : rhs , startRegion : startRegion , endRegion : rhs . endRegion ) , startRegion : startRegion , endRegion : rhs . endRegion ) ;
}
}
if ( suffixExp is SuffixexpNode . Normal )
{
throw new Exception ( $"{startRegion}: Expected function call, got normal suffix expression" ) ;
}
if ( suffixExp is SuffixexpNode . Functioncall functioncall )
{
return new StatNode . Functioncall ( node : functioncall . node , startRegion : functioncall . startRegion , endRegion : functioncall . endRegion ) ;
}
}
}
break ;
default :
{
throw new Exception ( $"Unexpected token {tokens[index]} at {startRegion}" ) ;
}
}
throw new NotImplementedException ( ) ;
}
private VarNode ParseVar ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
return SuffixExpToVar ( ParseSuffixExp ( tokens ) ) ;
2024-02-01 02:20:22 +01:00
}
2024-02-21 13:49:04 +01:00
private static VarNode SuffixExpToVar ( SuffixexpNode suffixExp )
2024-02-01 02:20:22 +01:00
{
2024-02-21 13:49:04 +01:00
if ( suffixExp is not SuffixexpNode . Normal normal )
{
throw new Exception ( $"Expected a normal suffix expression to convert to var at {suffixExp.startRegion}-{suffixExp.endRegion}" ) ;
}
if ( normal . node . suffixes . Count = = 0 )
{
if ( normal . node . firstPart is not SuffixexpFirstPart . Name name )
{
throw new Exception ( $"Expected a name as first part of suffix expression to convert to var at {normal.node.firstPart.startRegion}-{normal.node.firstPart.endRegion}" ) ;
}
return new VarNode . Name ( name : name . name , startRegion : suffixExp . startRegion , endRegion : suffixExp . endRegion ) ;
}
SuffixexpSuffix last = normal . node . suffixes [ ^ 1 ] ;
2024-02-21 15:09:55 +01:00
_ = normal . node . suffixes . Remove ( last ) ;
2024-02-21 13:49:04 +01:00
return last switch
{
SuffixexpSuffix . Dot dot = > new VarNode . Member ( node : new ( name : dot . name , value : normal , startRegion : suffixExp . startRegion , endRegion : suffixExp . endRegion ) , startRegion : suffixExp . startRegion , endRegion : dot . endRegion ) ,
SuffixexpSuffix . Indexed indexed = > new VarNode . Indexed ( node : new ( index : indexed . node , value : normal , startRegion : suffixExp . startRegion , endRegion : suffixExp . endRegion ) , startRegion : suffixExp . startRegion , endRegion : indexed . endRegion ) ,
_ = > throw new Exception ( $"Expected dot or indexed suffix expression to convert to var at {last.startRegion}-{last.endRegion}" )
} ;
2024-02-01 02:20:22 +01:00
}
private SuffixexpNode ParseSuffixExp ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
// primaryexp { '.' 'Name' | '[' exp']' | ':' 'Name' args | args }
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
SuffixexpFirstPart firstPart ;
switch ( tokens [ index ] . type )
{
case TokenType . Name :
{
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
firstPart = new SuffixexpFirstPart . Name ( name , startRegion , startRegion ) ;
}
break ;
case TokenType . RoundOpen :
{
index + = 1 ;
ExpNode inner = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `)` to close bracketed expression starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . RoundClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `)` to close bracketed expression at {startRegion}, got {tokens[index].type}" ) ;
}
firstPart = new SuffixexpFirstPart . BracketedExp ( node : inner , startRegion : startRegion , endRegion : tokens [ index ] . region ) ;
index + = 1 ;
}
break ;
default :
throw new Exception ( $"{startRegion}: Expected either `)` or name as first part of suffix-expression, got {tokens[index].type}" ) ;
}
List < SuffixexpSuffix > suffixes = [ ] ;
bool shouldContinue = true ;
while ( shouldContinue & & index < tokens . Length )
{
CodeRegion suffixStartRegion = tokens [ index ] . region ;
switch ( tokens [ index ] . type )
{
case TokenType . Dot :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name in dotted suffix of suffix expression starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name in dotted suffix of suffix expression at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion suffixEndRegion = tokens [ index ] . region ;
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
suffixes . Add ( new SuffixexpSuffix . Dot ( name , startRegion : suffixStartRegion , endRegion : suffixEndRegion ) ) ;
}
break ;
case TokenType . SquareOpen :
{
index + = 1 ;
ExpNode inner = ParseExp ( tokens ) ;
suffixes . Add ( new SuffixexpSuffix . Indexed ( node : inner , startRegion : suffixStartRegion , endRegion : inner . endRegion ) ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `]` to close indexed suffix of suffix-expression starting at {suffixStartRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . SquareClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `]` to close indexed suffix of suffix-expression at {suffixStartRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
}
break ;
case TokenType . Colon :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name as first arg after `:` in args suffix in suffix-expression starting at {suffixStartRegion}" ) ;
}
2024-02-21 15:10:37 +01:00
if ( tokens [ index ] . type ! = TokenType . Name )
2024-02-21 13:49:04 +01:00
{
throw new Exception ( $"{tokens[index].region}: Expected name as first arg after `:` in args suffix in suffix-expression at {suffixStartRegion}, got {tokens[index].type}" ) ;
}
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
ArgsNode args = ParseArgs ( tokens ) ;
suffixes . Add ( new SuffixexpSuffix . ArgsFirstArg ( new ( name , rest : args , startRegion : suffixStartRegion , endRegion : args . endRegion ) , startRegion : suffixStartRegion , endRegion : args . endRegion ) ) ;
}
break ;
case TokenType . RoundOpen :
case TokenType . CurlyOpen :
case TokenType . StringLiteral :
{
ArgsNode args = ParseArgs ( tokens ) ;
suffixes . Add ( new SuffixexpSuffix . Args ( node : args , startRegion : suffixStartRegion , endRegion : args . endRegion ) ) ;
}
break ;
default :
{
shouldContinue = false ;
}
break ;
}
}
CodeRegion endRegion ;
if ( suffixes . Count > 0 )
{
endRegion = suffixes [ ^ 1 ] . endRegion ;
SuffixexpNode ? ret = suffixes [ ^ 1 ] switch
{
SuffixexpSuffix . Args args = > new SuffixexpNode . Functioncall (
node : new (
function : new SuffixexpNode . Normal (
node : new NormalSuffixNode ( firstPart , suffixes [ . . ^ 1 ] , startRegion , args . endRegion ) ,
startRegion : startRegion ,
endRegion : args . endRegion
) ,
args : args . node ,
objectArg : null ,
startRegion : startRegion ,
endRegion : args . endRegion
) ,
startRegion : startRegion ,
endRegion : args . endRegion
) ,
SuffixexpSuffix . ArgsFirstArg node = > new SuffixexpNode . Functioncall (
node : new (
function : new SuffixexpNode . Normal (
node : new NormalSuffixNode ( firstPart : firstPart , suffixes : suffixes [ . . ^ 1 ] , startRegion , node . endRegion ) ,
startRegion : startRegion ,
endRegion : node . endRegion
) ,
objectArg : node . node . name ,
args : node . node . rest ,
startRegion : startRegion ,
endRegion : node . endRegion
) ,
startRegion : startRegion ,
endRegion : node . endRegion
) ,
_ = > null ,
} ;
if ( ret is not null )
{
return ret ;
}
}
else
{
endRegion = firstPart . endRegion ;
}
return new SuffixexpNode . Normal (
node : new ( firstPart : firstPart , suffixes : suffixes , startRegion : startRegion , endRegion : endRegion ) ,
startRegion : startRegion ,
endRegion : endRegion
) ;
}
private ArgsNode ParseArgs ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `(`, `{{` or string to start args" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
switch ( tokens [ index ] . type )
{
case TokenType . RoundOpen :
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected explist or `)` to continue args starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type = = TokenType . RoundClosed )
{
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new ArgsNode . Bracketed ( null , startRegion : startRegion , endRegion : endRegion ) ;
}
ExplistNode exps = ParseExplist ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `)` to close args starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . RoundClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `)` to close args starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
return new ArgsNode . Bracketed ( node : exps , startRegion : startRegion , endRegion : exps . endRegion ) ;
}
case TokenType . CurlyOpen :
{
TableconstructorNode node = ParseTableconstructor ( tokens ) ;
return new ArgsNode . Tableconstructor ( node : node , startRegion : startRegion , endRegion : node . endRegion ) ;
}
case TokenType . StringLiteral :
{
string value = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
return new ArgsNode . Literal ( name : value , startRegion : startRegion , endRegion : startRegion ) ;
}
default :
throw new Exception ( $"{tokens[index].region}: Expected explist or `)` to continue args starting at {startRegion}" ) ;
}
}
private TableconstructorNode ParseTableconstructor ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `{{` to start tableconstructor" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type ! = TokenType . CurlyOpen )
{
throw new Exception ( $"{startRegion}: Expected `{{` to start tableconstructor, got {tokens[index].type}" ) ;
}
index + = 1 ;
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . CurlyClosed )
{
CodeRegion emptyEndRegion = tokens [ index ] . region ;
index + = 1 ;
return new TableconstructorNode ( exps : null , startRegion : startRegion , endRegion : emptyEndRegion ) ;
}
FieldlistNode fields = ParseFieldlist ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `}}` to close tableconstructor starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . CurlyClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `}}` to close tableconstructor starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new TableconstructorNode ( exps : fields , startRegion : startRegion , endRegion : endRegion ) ;
}
private FieldlistNode ParseFieldlist ( Token [ ] tokens )
{
List < FieldNode > fields = [ ParseField ( tokens ) ] ;
while ( index < tokens . Length & & IsFieldsep ( tokens [ index ] ) )
{
index + = 1 ;
2024-02-21 16:01:58 +01:00
if ( index < tokens . Length & & tokens [ index ] . type is TokenType . SquareOpen or
TokenType . Name or TokenType . Nil or TokenType . True or TokenType . False or TokenType . Numeral or TokenType . StringLiteral or
TokenType . DotDotDot or TokenType . CurlyOpen or TokenType . Function or TokenType . Minus or TokenType . Hash or TokenType . Not or TokenType . Nil or TokenType . RoundOpen )
{
fields . Add ( ParseField ( tokens ) ) ;
}
2024-02-21 13:49:04 +01:00
}
// NOTE: Since at least 1 field is parsed the list accesses are safe
return new FieldlistNode ( exps : fields , startRegion : fields [ 0 ] . startRegion , endRegion : fields [ ^ 1 ] . endRegion ) ;
}
private static bool IsFieldsep ( Token token ) = > token . type is TokenType . Comma or TokenType . Semicolon ;
private FieldNode ParseField ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `[` or name to start field" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
switch ( tokens [ index ] . type )
{
case TokenType . SquareOpen :
{
index + = 1 ;
ExpNode indexNode = ParseExp ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `]` to close indexed field in indexed field assignment starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . SquareClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `]` to close indexed field starting in indexed field assignment at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `=` to continue indexed field assignment starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Equals )
{
throw new Exception ( $"{tokens[index].region}: Expected `=` to continue indexed field assignment starting at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
ExpNode rhs = ParseExp ( tokens ) ;
return new FieldNode . IndexedAssignment ( node : new ( index : indexNode , rhs : rhs , startRegion : startRegion , endRegion : rhs . endRegion ) , startRegion : startRegion , endRegion : rhs . endRegion ) ;
}
case TokenType . Name :
{
if ( index + 1 < tokens . Length & & tokens [ index + 1 ] . type = = TokenType . Equals )
{
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 2 ;
ExpNode rhs = ParseExp ( tokens ) ;
return new FieldNode . Assignment ( node : new ( lhs : name , rhs : rhs , startRegion : startRegion , endRegion : rhs . endRegion ) , startRegion : startRegion , endRegion : rhs . endRegion ) ;
}
ExpNode exp = ParseExp ( tokens ) ;
return new FieldNode . Exp ( node : exp , startRegion : startRegion , endRegion : exp . endRegion ) ;
}
default :
{
ExpNode exp = ParseExp ( tokens ) ;
return new FieldNode . Exp ( node : exp , startRegion : startRegion , endRegion : exp . endRegion ) ;
}
}
2024-02-01 02:20:22 +01:00
}
private AttnamelistNode ParseAttnamelist ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
List < AttnameNode > attnames = [ ParseAttname ( tokens ) ] ;
while ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
attnames . Add ( ParseAttname ( tokens ) ) ;
}
// NOTE: Since at least 1 attname is parsed the list accesses are safe
return new ( attnames : attnames , startRegion : attnames [ 0 ] . startRegion , endRegion : attnames [ ^ 1 ] . endRegion ) ;
}
private AttnameNode ParseAttname ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name to start attname" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name to start attname at {startRegion}, got {tokens[index].type}" ) ;
}
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Lt )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected attribute name of attname starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected attribute name of attname at {startRegion}, got {tokens[index].type}" ) ;
}
string attribute = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `>` to close attribute of attname starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Gt )
{
throw new Exception ( $"{tokens[index].region}: Expected `>` to close attribute of attname starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new AttnameNode ( name : name , attribute : attribute , startRegion : startRegion , endRegion : endRegion ) ;
}
return new AttnameNode ( name : name , attribute : null , startRegion : startRegion , endRegion : startRegion ) ;
2024-02-01 02:20:22 +01:00
}
private FuncbodyNode ParseFuncbody ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `(` to start funcbody" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type ! = TokenType . RoundOpen )
{
throw new Exception ( $"{tokens[index].region}: Expected `(` to start funcbody at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
ParlistNode ? pars ;
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . RoundClosed )
{
index + = 1 ;
pars = null ;
}
else
{
pars = ParseParlist ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `)` to close parlist of funcbody starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . RoundClosed )
{
throw new Exception ( $"{tokens[index].region}: Expected `)` to close parlist of funcbody at {startRegion}, got {tokens[index].type}" ) ;
}
index + = 1 ;
}
BlockNode body = ParseBlock ( tokens ) ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `end` to close funcbody starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . End )
{
throw new Exception ( $"{tokens[index].region}: Expected `end` to close funcbody starting at {startRegion}, got {tokens[index].type}" ) ;
}
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new FuncbodyNode ( pars : pars , body : body , startRegion : startRegion , endRegion : endRegion ) ;
}
private ParlistNode ParseParlist ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `...` or name to start parlist" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type = = TokenType . DotDotDot )
{
2024-02-21 15:11:17 +01:00
index + = 1 ;
2024-02-21 13:49:04 +01:00
return new ParlistNode ( names : [ ] , hasVarargs : true , startRegion : startRegion , endRegion : startRegion ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{startRegion}: Expected `...` or name to start parlist, got {tokens[index].type}" ) ;
}
List < string > names = [ ( ( Token . StringData ) tokens [ index ] . data ! ) . data ] ;
index + = 1 ;
while ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `...` or name to continue parlist starting at {startRegion}" ) ;
}
switch ( tokens [ index ] . type )
{
case TokenType . Name :
{
names . Add ( ( ( Token . StringData ) tokens [ index ] . data ! ) . data ) ;
index + = 1 ;
}
break ;
case TokenType . DotDotDot :
{
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new ParlistNode ( names : names , hasVarargs : true , startRegion : startRegion , endRegion : endRegion ) ;
} ;
default :
{
throw new Exception ( $"{tokens[index].region}: Expected `...` or name to continue parlist starting at {startRegion}, got {tokens[index].type}" ) ;
}
}
}
return new ParlistNode ( names : names , hasVarargs : false , startRegion : startRegion , endRegion : tokens [ index - 1 ] . region ) ;
2024-02-01 02:20:22 +01:00
}
private FuncnameNode ParseFuncname ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name to start funcname" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{startRegion}: Expected name to start funcname, got {tokens[index].type}" ) ;
}
string name = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
List < string > dottedNames = [ ] ;
while ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Dot )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name in dotted funcname starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name in dotted funcname starting at {startRegion}, got {tokens[index].type}" ) ;
}
dottedNames . Add ( ( ( Token . StringData ) tokens [ index ] . data ! ) . data ) ;
2024-02-21 15:11:45 +01:00
index + = 1 ;
2024-02-21 13:49:04 +01:00
}
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Colon )
{
index + = 1 ;
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected name as first arg name after `:` in funcname starting at {startRegion}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
throw new Exception ( $"{tokens[index].region}: Expected name as first arg name after `:` in funcname starting at {startRegion}, got {tokens[index].type}" ) ;
}
string firstArg = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
CodeRegion endRegion = tokens [ index ] . region ;
index + = 1 ;
return new FuncnameNode ( name : name , dottedNames : dottedNames , firstArg : firstArg , startRegion : startRegion , endRegion : endRegion ) ;
}
return new FuncnameNode ( name : name , dottedNames : dottedNames , firstArg : null , startRegion : startRegion , endRegion : tokens [ index - 1 ] . region ) ;
2024-02-01 02:20:22 +01:00
}
private ExplistNode ParseExplist ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
List < ExpNode > exps = [ ParseExp ( tokens ) ] ;
while ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Comma )
{
index + = 1 ;
exps . Add ( ParseExp ( tokens ) ) ;
}
return new ExplistNode ( exps : exps , startRegion : exps [ 0 ] . startRegion , endRegion : exps [ ^ 1 ] . endRegion ) ;
2024-02-01 02:20:22 +01:00
}
private ExpNode ParseExp ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
ExpNode lhs = ParseExpPrimary ( tokens ) ;
return ParseExpPrecedence ( tokens , lhs , 0 ) ;
}
private ExpNode ParseExpPrecedence ( Token [ ] tokens , ExpNode lhs , int minPrecedence )
{
ExpNode currentLhs = lhs ;
while ( index < tokens . Length & & IsBinop ( tokens [ index ] ) )
{
CodeRegion startRegion = tokens [ index ] . region ;
int precedence = GetPrecedence ( tokens [ index ] ) ;
if ( precedence < minPrecedence )
{
break ;
}
BinopType op = GetBinopType ( tokens [ index ] ) ;
index + = 1 ;
ExpNode rhs = ParseExpPrimary ( tokens ) ;
while ( index < tokens . Length & & IsBinop ( tokens [ index ] ) & & ( GetPrecedence ( tokens [ index ] ) > precedence | | ( GetPrecedence ( tokens [ index ] ) = = precedence & & IsRightAssociative ( tokens [ index ] ) ) ) )
{
int associativityBoost = ( GetPrecedence ( tokens [ index ] ) = = precedence ) ? 0 : 1 ;
rhs = ParseExpPrecedence ( tokens , lhs : rhs , minPrecedence : precedence + associativityBoost ) ;
}
currentLhs = new ExpNode . Binop ( node : new ( lhs : currentLhs , type : op , rhs : rhs , startRegion : startRegion , endRegion : rhs . endRegion ) , startRegion : startRegion , endRegion : rhs . endRegion ) ;
}
return currentLhs ;
}
private static bool IsRightAssociative ( Token token ) = > token . type is TokenType . DotDot or TokenType . Caret ;
private static BinopType GetBinopType ( Token token ) = > token . type switch
{
TokenType . Or = > BinopType . LogicalOr ,
TokenType . And = > BinopType . LogicalAnd ,
TokenType . Lt = > BinopType . Lt ,
TokenType . Gt = > BinopType . Gt ,
TokenType . LtEquals = > BinopType . LtEquals ,
TokenType . GtEquals = > BinopType . GtEquals ,
TokenType . LtLt = > BinopType . Shl ,
TokenType . GtGt = > BinopType . Shr ,
TokenType . TildeEquals = > BinopType . NotEquals ,
TokenType . EqualsEquals = > BinopType . Equals ,
TokenType . Pipe = > BinopType . BinaryOr ,
TokenType . Tilde = > BinopType . BinaryNot ,
TokenType . Ampersand = > BinopType . BinaryAnd ,
TokenType . DotDot = > BinopType . Concat ,
TokenType . Plus = > BinopType . Add ,
TokenType . Minus = > BinopType . Sub ,
TokenType . Star = > BinopType . Mul ,
TokenType . Slash = > BinopType . Div ,
TokenType . SlashSlash = > BinopType . IntDiv ,
TokenType . Percent = > BinopType . Mod ,
TokenType . Caret = > BinopType . Exp ,
_ = > throw new Exception ( $"{token.region}: Expected binary operator with precedence, got {token.type}" ) ,
} ;
private static int GetPrecedence ( Token token ) = > token . type switch
{
TokenType . Or = > 2 ,
TokenType . And = > 4 ,
TokenType . Lt or TokenType . Gt or TokenType . LtEquals or TokenType . GtEquals or TokenType . TildeEquals or TokenType . EqualsEquals = > 6 ,
TokenType . Pipe = > 8 ,
TokenType . Tilde = > 10 ,
TokenType . Ampersand = > 12 ,
TokenType . LtLt or TokenType . GtGt = > 14 ,
TokenType . DotDot = > 16 ,
TokenType . Plus or TokenType . Minus = > 18 ,
TokenType . Star or TokenType . Slash or TokenType . SlashSlash or TokenType . Percent = > 20 ,
TokenType . Caret = > 22 ,
_ = > throw new Exception ( $"{token.region}: Expected binary operator with precedence, got {token.type}" ) ,
} ;
private static bool IsBinop ( Token token ) = > token . type switch
{
TokenType . Or or TokenType . And or TokenType . Lt or TokenType . Gt or TokenType . LtEquals or TokenType . GtEquals or TokenType . TildeEquals or TokenType . EqualsEquals or
TokenType . Pipe or TokenType . Tilde or TokenType . Ampersand or TokenType . LtLt or TokenType . GtGt or TokenType . DotDot or TokenType . Plus or TokenType . Minus or
TokenType . Star or TokenType . Slash or TokenType . SlashSlash or TokenType . Percent or TokenType . Caret = > true ,
_ = > false
} ;
private ExpNode ParseExpPrimary ( Token [ ] tokens )
{
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected primary expression (`nil`, `true`, `false`, numeral, string, `...`, `function`, `{{`, `#`, `not`, `~`)" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
switch ( tokens [ index ] . type )
{
case TokenType . Nil :
{
index + = 1 ;
return new ExpNode . Nil ( region : startRegion ) ;
}
case TokenType . True :
{
index + = 1 ;
return new ExpNode . True ( region : startRegion ) ;
}
case TokenType . False :
{
index + = 1 ;
return new ExpNode . False ( region : startRegion ) ;
}
case TokenType . Numeral :
{
INumeral numeral = ( ( Token . NumeralData ) tokens [ index ] . data ! ) . numeral ;
index + = 1 ;
return new ExpNode . Numeral ( value : numeral , region : startRegion ) ;
}
case TokenType . StringLiteral :
{
string value = ( ( Token . StringData ) tokens [ index ] . data ! ) . data ;
index + = 1 ;
return new ExpNode . LiteralString ( value : value , region : startRegion ) ;
}
case TokenType . DotDotDot :
{
index + = 1 ;
return new ExpNode . Varargs ( region : startRegion ) ;
}
case TokenType . CurlyOpen :
{
TableconstructorNode inner = ParseTableconstructor ( tokens ) ;
return new ExpNode . Tableconstructor ( node : inner , startRegion : inner . startRegion , endRegion : inner . endRegion ) ;
}
case TokenType . Function :
{
index + = 1 ;
FuncbodyNode body = ParseFuncbody ( tokens ) ;
return new ExpNode . Functiondef ( node : body , startRegion : startRegion , endRegion : body . endRegion ) ;
}
case TokenType . Minus :
{
index + = 1 ;
ExpNode unop = ParseExp ( tokens ) ;
return new ExpNode . Unop ( node : new ( type : UnopType . Minus , exp : unop , startRegion : startRegion , endRegion : unop . endRegion ) , startRegion : startRegion , endRegion : unop . endRegion ) ;
}
case TokenType . Hash :
{
index + = 1 ;
ExpNode unop = ParseExp ( tokens ) ;
return new ExpNode . Unop ( node : new ( type : UnopType . Length , exp : unop , startRegion : startRegion , endRegion : unop . endRegion ) , startRegion : startRegion , endRegion : unop . endRegion ) ;
}
case TokenType . Not :
{
index + = 1 ;
ExpNode unop = ParseExp ( tokens ) ;
return new ExpNode . Unop ( node : new ( type : UnopType . LogicalNot , exp : unop , startRegion : startRegion , endRegion : unop . endRegion ) , startRegion : startRegion , endRegion : unop . endRegion ) ;
}
case TokenType . Tilde :
{
index + = 1 ;
ExpNode unop = ParseExp ( tokens ) ;
return new ExpNode . Unop ( node : new ( type : UnopType . BinaryNot , exp : unop , startRegion : startRegion , endRegion : unop . endRegion ) , startRegion : startRegion , endRegion : unop . endRegion ) ;
}
default :
{
SuffixexpNode suffixexp = ParseSuffixExp ( tokens ) ;
return new ExpNode . Suffixexp ( node : suffixexp , startRegion : suffixexp . startRegion , endRegion : suffixexp . endRegion ) ;
}
}
2024-02-01 02:20:22 +01:00
}
private RetstatNode ParseRetstat ( Token [ ] tokens )
{
2024-02-21 13:49:04 +01:00
if ( index > = tokens . Length )
{
throw new Exception ( $"Index {index} out of bounds of {tokens.Length}, expected `return` to start retstat" ) ;
}
CodeRegion startRegion = tokens [ index ] . region ;
if ( tokens [ index ] . type ! = TokenType . Return )
{
throw new Exception ( $"{startRegion}: Expected `return` to start retstat, got {tokens[index].type}" ) ;
}
index + = 1 ;
if ( index > = tokens . Length )
{
return new RetstatNode ( values : null , startRegion : startRegion , endRegion : startRegion ) ;
}
if ( tokens [ index ] . type is TokenType . Semicolon or TokenType . Else or TokenType . Elseif or TokenType . End )
{
CodeRegion emptyEndRegion ;
if ( tokens [ index ] . type = = TokenType . Semicolon )
{
emptyEndRegion = tokens [ index ] . region ;
index + = 1 ;
}
else
{
emptyEndRegion = startRegion ;
}
return new RetstatNode ( values : null , startRegion : startRegion , endRegion : emptyEndRegion ) ;
}
ExplistNode values = ParseExplist ( tokens ) ;
CodeRegion endRegion ;
if ( index < tokens . Length & & tokens [ index ] . type = = TokenType . Semicolon )
{
endRegion = tokens [ index ] . region ;
index + = 1 ;
}
else
{
endRegion = values . endRegion ;
}
return new RetstatNode ( values : values , startRegion : startRegion , endRegion : endRegion ) ;
2024-02-01 02:20:22 +01:00
}
}