2024-02-21 13:45:54 +01:00
using System ;
using System.Collections.Generic ;
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 ;
}
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 ;
}
}
public class RetstatNode ( CodeRegion startRegion , CodeRegion endRegion )
{
public ExplistNode ? values ;
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 ;
}
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 ;
}
}
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 ;
}
}
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 ;
}
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 ;
}
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 ;
}
}
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 ;
}
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 & &
tokens [ index ] . type ! = TokenType . Else )
{
stats . Add ( ParseStat ( tokens ) ) ;
}
BlockNode ret = new ( stats : stats , startRegion : startRegion , endRegion : stats [ ^ 1 ] . endRegion ) ;
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 ) ;
if ( tokens [ index ] . type = = TokenType . Then )
{
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}" ) ;
}
if ( tokens [ index ] . type ! = TokenType . Name )
{
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 )
{
throw new NotImplementedException ( ) ;
}
private VarNode SuffixExpToVar ( SuffixexpNode suffixExp )
{
throw new NotImplementedException ( ) ;
}
private SuffixexpNode ParseSuffixExp ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private AttnamelistNode ParseAttnamelist ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private FuncbodyNode ParseFuncbody ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private FuncnameNode ParseFuncname ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private ExplistNode ParseExplist ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private ExpNode ParseExp ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
private RetstatNode ParseRetstat ( Token [ ] tokens )
{
throw new NotImplementedException ( ) ;
}
}