LangStudies/App/EoI/Scripts/Parser.gd

467 lines
10 KiB
GDScript3
Raw Normal View History

2022-07-23 23:56:37 -07:00
extends Object
# ---------------------------------------------------------- UTILITIES
var ErrorOut
func check( condition : bool, message : String):
assert(condition, message)
if ! condition:
ErrorOut.text = "Eva - Error: " + message
func throw( message ):
assert(false, message)
ErrorOut.text = "Eva - Error: " + message
# ---------------------------------------------------------- UTILITIES END
class_name Parser
# ---------------------------------------------------------- AST Node
const NType = \
{
program = "Program",
2022-07-24 04:54:17 -07:00
empty = "Empty",
2022-07-23 23:56:37 -07:00
block = "Scope Block",
2022-07-24 01:36:18 -07:00
conditional = "Conditional",
2022-07-24 18:47:00 -07:00
expr_Switch = "Expression Switch",
2022-07-24 01:36:18 -07:00
expr_While = "Expression While",
2022-07-24 18:47:00 -07:00
expr_For = "Expression For",
2022-07-24 01:36:18 -07:00
2022-07-23 23:56:37 -07:00
literal_Number = "Literal: Number",
literal_String = "Literal: String",
op_Assign = "Assignment",
2022-07-24 04:54:17 -07:00
op_Fn = "Function Call",
2022-07-23 23:56:37 -07:00
2022-07-24 18:47:00 -07:00
op_Add = "+",
op_Sub = "-",
op_Mult = "*",
op_Div = "/",
op_Increment = "++",
op_Decrement = "--",
2022-07-24 01:36:18 -07:00
op_Greater = ">",
op_GreaterEqual = ">=",
op_Lesser = "<",
op_LesserEqual = "<=",
2022-07-24 07:33:26 -07:00
op_Equal = "=",
op_NotEqual = "!=",
2022-07-23 23:56:37 -07:00
2022-07-24 06:50:38 -07:00
fn_Print = "Print",
fn_User = "User Function",
fn_Lambda = "Lambda Function",
fn_IIL = "Lambda Function Immediate Invocation",
2022-07-24 04:54:17 -07:00
fn_Params = "Function Parameters",
2022-07-24 06:50:38 -07:00
fn_Body = "Function Body",
2022-07-23 23:56:37 -07:00
identifier = "Identifier",
2022-07-24 04:54:17 -07:00
variable = "Variable"
2022-07-23 23:56:37 -07:00
}
class ASTNode:
var Data : Array
2022-07-24 06:50:38 -07:00
func get_class() :
return "ASTNode"
2022-07-23 23:56:37 -07:00
func add_Expr( expr ):
Data.append(expr)
func add_TokenValue( token ):
Data.append( token.Value )
func set_Type( nType ):
Data.append(nType)
func arg( id ):
return Data[id]
func num_args():
return Data.size() - 1
func type():
return Data[0]
2022-07-24 18:47:00 -07:00
func is_op_Relation():
match type():
NType.op_Greater: return true
NType.op_Lesser: return true
NType.op_GreaterEqual: return true
NType.op_LesserEqual: return true
NType.op_Equal: return true
NType.op_NotEqual: return true
_: return false
2022-07-23 23:56:37 -07:00
func is_op_Numeric():
match type():
NType.op_Add: return true
NType.op_Sub: return true
NType.op_Mult: return true
NType.op_Div: return true
2022-07-24 18:47:00 -07:00
NType.op_Increment: return true
NType.op_Decrement: return true
2022-07-23 23:56:37 -07:00
_: return false
func is_Number():
return type() == NType.literal_Number
func is_String():
return type() == NType.literal_String
func string():
return arg(1).substr(1, arg(1).length() -2)
# Serialization ----------------------------------------------------
func array_Serialize(array, fn_objSerializer) :
var result = []
for entry in array :
if typeof(entry) == TYPE_ARRAY :
result.append( array_Serialize( entry, fn_objSerializer ))
elif typeof(entry) == TYPE_OBJECT :
2022-07-24 06:50:38 -07:00
if entry.get_class() == "Eva":
result.append(entry)
else:
fn_objSerializer.set_instance(entry)
result.append( fn_objSerializer.call_func() )
2022-07-23 23:56:37 -07:00
else :
result.append( entry )
return result
func to_SExpression():
var \
to_SExpression_Fn = FuncRef.new()
to_SExpression_Fn.set_function("to_SExpression")
return array_Serialize( self.Data, to_SExpression_Fn )
# Serialization END -------------------------------------------------
# ---------------------------------------------------------- AST Node END
const SLexer = preload("Lexer.gd")
const TType = SLexer.TType
var Lexer : SLexer
var NextToken : SLexer.Token
# Gets the next token only if the current token is the specified intended token (tokenType)
func eat(tokenType):
var currToken = NextToken
check(currToken != null, "Parser - eat: NextToken was null")
var assertStrTmplt = "Parser - eat: Unexpected token: {value}, expected: {type}"
var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType})
check(currToken.Type == tokenType, assertStr)
NextToken = Lexer.next_Token()
return currToken
func parse():
var \
node = ASTNode.new()
node.set_Type(NType.program)
while NextToken != null :
if NextToken.Type == TType.def_Start:
node.add_Expr( parse_Expression() )
elif NextToken.Type == TType.identifier:
node.add_Expr( parse_Identifier() )
elif NextToken.is_Literal():
2022-07-24 06:50:38 -07:00
node.add_Expr( parse_Literal() )
2022-07-23 23:56:37 -07:00
return node
func parse_Expression():
eat(TType.def_Start)
var node : ASTNode
match NextToken.Type :
TType.def_Block:
2022-07-24 18:47:00 -07:00
node = parse_Simple(TType.def_Block, NType.block)
2022-07-24 01:36:18 -07:00
TType.def_Cond:
2022-07-24 18:47:00 -07:00
node = parse_Simple(TType.def_cond, NType.conditional)
TType.def_Switch:
node = parse_Switch()
2022-07-24 01:36:18 -07:00
TType.def_While:
2022-07-24 18:47:00 -07:00
node = parse_Simple(TType.def_While, NType.expr_While)
TType.def_For:
node = parse_Simple(TType.def_For, NType.expr_For)
2022-07-23 23:56:37 -07:00
TType.def_Var:
node = parse_Variable()
2022-07-24 04:54:17 -07:00
TType.def_Func:
node = parse_fn_User()
2022-07-24 06:50:38 -07:00
TType.def_Lambda:
node = parse_fn_Lambda()
2022-07-23 23:56:37 -07:00
TType.fn_Print:
2022-07-24 18:47:00 -07:00
node = parse_Simple(TType.fn_Print, NType.fn_Print)
2022-07-23 23:56:37 -07:00
TType.op_Assgin:
node = parse_op_Assign()
TType.op_Numeric:
node = parse_op_Numeric()
2022-07-24 01:36:18 -07:00
TType.op_Relational:
node = parse_op_Relational()
2022-07-24 07:33:26 -07:00
TType.op_Equality:
node = ASTNode.new()
match NextToken.Value:
NType.op_Equal:
node.set_Type(NType.op_Equal)
NType.op_NotEqual:
node.set_Type(NType.op_NotEqual)
eat(TType.op_Equality)
2022-07-24 04:54:17 -07:00
TType.identifier:
node = parse_op_Fn()
2022-07-24 06:50:38 -07:00
TType.def_Start:
node = parse_fn_IIL()
2022-07-23 23:56:37 -07:00
while NextToken.Type != TType.def_End:
if NextToken.Type == TType.def_Start:
node.add_Expr( parse_Expression() )
elif NextToken.Type == TType.identifier:
node.add_Expr( parse_Identifier() )
else :
node.add_Expr( parse_Literal() )
eat(TType.def_End)
2022-07-24 04:54:17 -07:00
if node == null:
node = ASTNode.new()
node.set_Type(NType.empty)
2022-07-23 23:56:37 -07:00
return node
2022-07-24 18:47:00 -07:00
func parse_Simple(tType, nType):
2022-07-23 23:56:37 -07:00
var \
node = ASTNode.new()
2022-07-24 18:47:00 -07:00
node.set_Type(nType)
eat(tType)
2022-07-23 23:56:37 -07:00
return node
2022-07-24 18:47:00 -07:00
func parse_Switch():
2022-07-24 01:36:18 -07:00
var \
node = ASTNode.new()
2022-07-24 18:47:00 -07:00
node.set_Type(NType.expr_Switch)
eat(TType.def_Switch)
2022-07-24 01:36:18 -07:00
return node
2022-07-23 23:56:37 -07:00
func parse_Variable():
var \
node = ASTNode.new()
node.set_Type(NType.variable)
eat(TType.def_Var)
check( NextToken.Type == TType.identifier,
String("Parser - parse_Variable: NextToken should have been identifier. TokenData - Type: {type} Value: {value}") \
.format({"type" : NextToken.Type, "value" : NextToken.Value })
)
node.add_TokenValue( NextToken )
eat(TType.identifier)
2022-07-24 04:54:17 -07:00
return node
2022-07-23 23:56:37 -07:00
2022-07-24 04:54:17 -07:00
func parse_fn_User():
var \
node = ASTNode.new()
node.set_Type(NType.fn_User)
eat(TType.def_Func)
check( NextToken.Type == TType.identifier,
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
.format({"type" : NextToken.Type, "value" : NextToken.Value })
)
node.add_TokenValue( NextToken )
eat(TType.identifier)
# Parameters
var \
pNode = ASTNode.new()
pNode.set_Type(NType.fn_Params)
eat(TType.def_Start)
while NextToken.Type != TType.def_End:
check( NextToken.Type == TType.identifier,
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
.format({"type" : NextToken.Type, "value" : NextToken.Value })
)
2022-07-23 23:56:37 -07:00
2022-07-24 04:54:17 -07:00
pNode.add_TokenValue(NextToken)
eat(TType.identifier)
eat(TType.def_End)
2022-07-24 06:50:38 -07:00
var \
bNode = ASTNode.new()
bNode.set_Type(NType.fn_Body)
while NextToken.Type != TType.def_End:
bNode.add_Expr( parse_Expression() )
2022-07-24 04:54:17 -07:00
node.add_Expr( pNode )
2022-07-24 06:50:38 -07:00
node.add_Expr( bNode )
return node
func parse_fn_Lambda():
var \
node = ASTNode.new()
node.set_Type(NType.fn_Lambda)
eat(TType.def_Lambda)
# Parameters
var \
pNode = ASTNode.new()
pNode.set_Type(NType.fn_Params)
eat(TType.def_Start)
while NextToken.Type != TType.def_End:
check( NextToken.Type == TType.identifier,
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
.format({"type" : NextToken.Type, "value" : NextToken.Value })
)
pNode.add_TokenValue(NextToken)
eat(TType.identifier)
eat(TType.def_End)
var \
bNode = ASTNode.new()
bNode.set_Type(NType.fn_Body)
while NextToken.Type != TType.def_End:
bNode.add_Expr( parse_Expression() )
node.add_Expr( pNode )
node.add_Expr( bNode )
2022-07-23 23:56:37 -07:00
return node
2022-07-24 06:50:38 -07:00
func parse_fn_IIL():
var \
node = ASTNode.new()
node.set_Type(NType.fn_IIL)
# Lambda
node.add_Expr( parse_Expression() )
return node
2022-07-23 23:56:37 -07:00
func parse_Identifier():
var \
node = ASTNode.new()
node.set_Type(NType.identifier)
node.add_TokenValue(NextToken)
eat(TType.identifier)
return node
func parse_op_Assign():
var \
node = ASTNode.new()
node.set_Type(NType.op_Assign)
eat(TType.op_Assgin)
check( NextToken.Type == TType.identifier,
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
.format({"type" : NextToken.Type, "value" : NextToken.Value })
)
node.add_TokenValue( NextToken )
eat(TType.identifier)
if NextToken.is_Literal() :
node.add_Expr( parse_Literal() )
elif NextToken.Type == TType.def_Start :
node.add_Expr( parse_Expression() )
return node
2022-07-24 01:36:18 -07:00
2022-07-23 23:56:37 -07:00
func parse_op_Numeric():
var node = ASTNode.new()
match NextToken.Value:
NType.op_Add:
node.set_Type(NType.op_Add)
NType.op_Sub:
node.set_Type(NType.op_Sub)
NType.op_Mult:
node.set_Type(NType.op_Mult)
NType.op_Div:
node.set_Type(NType.op_Div)
2022-07-24 18:47:00 -07:00
NType.op_Increment:
node.set_Type(NType.op_Increment)
NType.op_Decrement:
node.set_Type(NType.op_Decrement)
2022-07-23 23:56:37 -07:00
eat(TType.op_Numeric)
return node
2022-07-24 01:36:18 -07:00
func parse_op_Relational():
var node = ASTNode.new()
match NextToken.Value:
NType.op_Greater:
node.set_Type(NType.op_Greater)
NType.op_Lesser:
node.set_Type(NType.op_Lesser)
NType.op_GreaterEqual:
node.set_Type(NType.op_GreaterEqual)
NType.op_LesserEqual:
node.set_Type(NType.op_LesserEqual)
eat(TType.op_Relational)
return node
2022-07-24 04:54:17 -07:00
func parse_op_Fn():
var \
node = ASTNode.new()
node.set_Type(NType.op_Fn)
node.add_TokenValue( NextToken )
eat(TType.identifier)
return node
2022-07-23 23:56:37 -07:00
func parse_Literal():
var node = ASTNode.new()
match NextToken.Type:
TType.literal_Number:
node.set_Type(NType.literal_Number)
node.add_TokenValue(NextToken)
eat(TType.literal_Number)
TType.literal_String:
node.set_Type(NType.literal_String)
node.add_TokenValue(NextToken)
eat(TType.literal_String)
return node
func _init(lexer, errorOut) :
ErrorOut = errorOut
Lexer = lexer
NextToken = Lexer.next_Token()
2022-07-24 01:36:18 -07:00