Start working on the parser
This commit is contained in:
parent
049a96191c
commit
02aab2e590
904
Parser.cs
Normal file
904
Parser.cs
Normal file
@ -0,0 +1,904 @@
|
||||
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) { }
|
||||
public class Numeral(INumeral value, CodeRegion startRegion, CodeRegion endRegion) : ExpNode(startRegion, endRegion)
|
||||
{
|
||||
public INumeral value = value;
|
||||
}
|
||||
public class LiteralString(string value, CodeRegion startRegion, CodeRegion endRegion) : ExpNode(startRegion, endRegion)
|
||||
{
|
||||
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;
|
||||
public class Dot(string name, CodeRegion startRegion, CodeRegion endRegion) : SuffixexpFirstPart(startRegion, endRegion)
|
||||
{
|
||||
public string name = name;
|
||||
}
|
||||
public class Indexed(ExpNode node, CodeRegion startRegion, CodeRegion endRegion) : SuffixexpFirstPart(startRegion, endRegion)
|
||||
{
|
||||
public ExpNode node = node;
|
||||
}
|
||||
public class Args(ArgsNode node, CodeRegion startRegion, CodeRegion endRegion) : SuffixexpFirstPart(startRegion, endRegion)
|
||||
{
|
||||
public ArgsNode node = node;
|
||||
}
|
||||
public class ArgsFirstArg(ArgsFirstArgNode node, CodeRegion startRegion, CodeRegion endRegion) : SuffixexpFirstPart(startRegion, endRegion)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user