Lecture 6 complete.

This commit is contained in:
Edward R. Gonzalez 2022-07-20 14:57:26 -04:00
parent f85c9615e4
commit de420a8111
8 changed files with 243 additions and 73 deletions

View File

@ -0,0 +1,13 @@
# Environment
A repository of variables and functions defined in a scope.
## Structure
Record: Actual storage, table, etc.
Parent: Optional refrence to a parent environment.
## Interface
Define: Variable
Assign: Value to a varaible
Lookup: Variable

View File

@ -18,16 +18,18 @@ var eva = preload("Eva.gd").new()
# UX -------------------------------------------------------- # UX --------------------------------------------------------
onready var Editor = get_node("Editor_TEdit") onready var Editor = get_node("Editor_TEdit")
onready var Output = get_node("Output_TEdit") onready var Output = get_node("Output_TEdit")
onready var Debug = get_node("Debug_TEdit")
onready var Eva_Btn = get_node("VBox/Eva_Interpret_Btn") onready var Eva_Btn = get_node("VBox/Eva_Interpret_Btn")
onready var Back_Btn = get_node("VBox/Back_Btn") onready var Back_Btn = get_node("VBox/Back_Btn")
func evaBtn_pressed(): func evaBtn_pressed():
eva.init(Editor.text) eva.init(Editor.text, Output)
var ast = eva.parse() var ast = eva.parse()
Output.text = eva.eval(ast) Output.text = eva.eval(ast)
Debug.text = JSON.print(eva.Records, "\t")
func backBtn_pressed(): func backBtn_pressed():
queue_free() queue_free()

View File

@ -2,7 +2,7 @@ extends Object
var SRegEx = preload("res://RegM/Scripts/SRegex.gd").new() var SRegEx = preload("res://RegM/Scripts/SRegex.gd").new()
# ---------------------------------------------------------- Lexer
const TType : Dictionary = \ const TType : Dictionary = \
{ {
fmt_S = "Formatting", fmt_S = "Formatting",
@ -11,11 +11,15 @@ const TType : Dictionary = \
def_Start = "Expression Start", def_Start = "Expression Start",
def_End = "Expression End", def_End = "Expression End",
def_Var = "Variable",
literal_Number = "LIteral: Number", literal_Number = "Literal: Number",
literal_String = "Literal: String", literal_String = "Literal: String",
operator = "Operator" op_Assgin = "Assignment",
op_Numeric = "op_Numeric",
identifier = "Identifier"
} }
const Spec : Dictionary = \ const Spec : Dictionary = \
@ -27,6 +31,7 @@ const Spec : Dictionary = \
TType.def_Start : "start \\(", TType.def_Start : "start \\(",
TType.def_End : "start \\)", TType.def_End : "start \\)",
TType.def_Var : "start \"var\"",
TType.literal_Number : \ TType.literal_Number : \
"""start """start
@ -36,7 +41,17 @@ const Spec : Dictionary = \
""", """,
TType.literal_String : "start \\\" !set( \\\" ).repeat(0-) \\\" ", TType.literal_String : "start \\\" !set( \\\" ).repeat(0-) \\\" ",
TType.operator : "start set(+ \\-)", TType.op_Assgin : "start \"set\"",
TType.op_Numeric : "start set(+ \\- * /)",
TType.identifier :
"""start
(
set(A-z).repeat(1-)
set(\\- _).repeat(0-1)
)
.repeat(0-1)
"""
} }
class Token: class Token:
@ -56,13 +71,16 @@ var TokenIndex : int = 0
func compile_regex(): func compile_regex():
for type in TType.values() : for type in TType.values() :
var \ var regex = RegEx.new()
regex = RegEx.new() var result = SRegEx.compile(Spec[type])
regex.compile( SRegEx.transpile(Spec[type]) )
regex.compile( result )
SpecRegex[type] = regex SpecRegex[type] = regex
func init(programSrcText): func init(programSrcText, errorOutput):
ErrorOutput = errorOutput
SourceText = programSrcText SourceText = programSrcText
Cursor = 0 Cursor = 0
TokenIndex = 0 TokenIndex = 0
@ -73,7 +91,6 @@ func init(programSrcText):
tokenize() tokenize()
func next_Token(): func next_Token():
var nextToken = null var nextToken = null
if Tokens.size() > TokenIndex : if Tokens.size() > TokenIndex :
@ -122,11 +139,11 @@ func tokenize():
break; break;
if error : if error :
var assertStrTmplt = "next_token: Source text not understood by tokenizer at Cursor pos: {value} -: {txt}" var assertStrTmplt = "Lexer - tokenize: Source text not understood by tokenizer at Cursor pos: {value} -: {txt}"
var assertStr = assertStrTmplt.format({"value" : Cursor, "txt" : srcLeft}) var assertStr = assertStrTmplt.format({"value" : Cursor, "txt" : srcLeft})
assert(true != true, assertStr) throw(assertStr)
return return
# ---------------------------------------------------------- Lexer # ---------------------------------------------------------- Lexer END
# ---------------------------------------------------------- Parser # ---------------------------------------------------------- Parser
@ -137,8 +154,15 @@ const NType = \
literal_Number = "Literal: Number", literal_Number = "Literal: Number",
literal_String = "Literal: String", literal_String = "Literal: String",
op_Assign = "Assignment",
op_Add = "+", op_Add = "+",
op_Mult = "*" op_Sub = "-",
op_Mult = "*",
op_Div = "/",
identifier = "Identifier",
variable = "Variable"
} }
class ASTNode: class ASTNode:
@ -171,7 +195,6 @@ class ASTNode:
func string(): func string():
return arg(1).substr(1, arg(1).length() -2) return arg(1).substr(1, arg(1).length() -2)
# Serialization ---------------------------------------------------- # Serialization ----------------------------------------------------
func array_Serialize(array, fn_objSerializer) : func array_Serialize(array, fn_objSerializer) :
var result = [] var result = []
@ -216,12 +239,12 @@ var NextToken : Token
func eat(tokenType): func eat(tokenType):
var currToken = NextToken var currToken = NextToken
assert(currToken != null, "eat: NextToken was null") check(currToken != null, "Parser - eat: NextToken was null")
var assertStrTmplt = "eat: Unexpected token: {value}, expected: {type}" var assertStrTmplt = "Parser - eat: Unexpected token: {value}, expected: {type}"
var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType}) var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType})
assert(currToken.Type == tokenType, assertStr) check(currToken.Type == tokenType, assertStr)
NextToken = next_Token() NextToken = next_Token()
@ -233,6 +256,9 @@ func parse():
if NextToken.Type == TType.def_Start: if NextToken.Type == TType.def_Start:
return parse_Expression() return parse_Expression()
if NextToken.Type == TType.identifier:
return parse_Identifier()
if NextToken.is_Literal(): if NextToken.is_Literal():
return parse_Literal() return parse_Literal()
@ -240,37 +266,102 @@ func parse_Expression():
eat(TType.def_Start) eat(TType.def_Start)
var node : ASTNode var node : ASTNode
if NextToken.Type == TType.operator: if NextToken.Type == TType.def_Var:
node = parse_Operator() node = parse_Variable()
if NextToken.Type == TType.op_Assgin:
node = parse_op_Assign()
elif NextToken.Type == TType.op_Numeric:
node = parse_op_Numeric()
var arg = 1 var arg = 1
while NextToken.Type != TType.def_End: while NextToken.Type != TType.def_End:
if NextToken.Type == TType.def_Start:
node.add_Expr( parse_Expression() )
else :
node.add_Expr( parse_Literal() ) node.add_Expr( parse_Literal() )
if NextToken.is_Literal(): elif NextToken.is_Literal():
node = parse_Literal() node = parse_Literal()
eat(TType.def_End) eat(TType.def_End)
return node return node
func parse_Operator(): func parse_Variable():
var \ var \
node = ASTNode.new() 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)
if NextToken.Type == TType.def_Start :
node.add_Expr( parse_Expression() )
else :
node.add_Expr( parse_Literal() )
return node
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.Value )
if NextToken.is_Literal() :
node.add_Expr( parse_Literal() )
elif NextToken.Type == TType.def_Start :
node.add_Expr( parse_Expression() )
return node
func parse_op_Numeric():
var node = ASTNode.new()
match NextToken.Value: match NextToken.Value:
NType.op_Add: NType.op_Add:
node.set_Type(NType.op_Add) node.set_Type(NType.op_Add)
NType.op_Sub:
node.set_Type(NType.op_Sub)
NType.op_Mult: NType.op_Mult:
node.set_Type(NType.op_Mult) node.set_Type(NType.op_Mult)
NType.op_Div:
node.set_Type(NType.op_Div)
eat(TType.operator) eat(TType.op_Numeric)
return node return node
func parse_Literal(): func parse_Literal():
var \ var node = ASTNode.new()
node = ASTNode.new()
match NextToken.Type: match NextToken.Type:
TType.literal_Number: TType.literal_Number:
@ -289,28 +380,93 @@ func parse_Literal():
# ---------------------------------------------------------- Parser END # ---------------------------------------------------------- Parser END
# ---------------------------------------------------------- Environment
var Records : Dictionary
func env_DefineVar(symbol : String, value) :
Records[symbol] = value
func env_Lookup(symbol : String) :
check(Records.has(symbol), String("Symbol not found in environment records"))
return Records[symbol]
# ---------------------------------------------------------- Environment END
class_name Eva class_name Eva
# ---------------------------------------------------------- GLOBALS # ---------------------------------------------------------- GLOBALS
var ErrorOutput
# ---------------------------------------------------------- GLOBALS END # ---------------------------------------------------------- GLOBALS END
# ---------------------------------------------------------- UTILITIES # ---------------------------------------------------------- UTILITIES
func check( condition : bool, message : String):
assert(condition, message)
ErrorOutput.text = "Eva - Error: " + message
func throw( message ): func throw( message ):
assert(false, message) assert(false, message)
ErrorOutput.text = "Eva - Error: " + message
# ---------------------------------------------------------- UTILITIES END # ---------------------------------------------------------- UTILITIES END
func eval( ast ): func eval( ast ):
if ast.is_Number() : if ast.type() == NType.identifier :
return float(ast.arg(1)) return env_Lookup( ast.arg(1) )
if ast.type() == NType.variable :
var symbol = ast.arg(1)
var value = eval( ast.arg(2) )
env_DefineVar(symbol, value)
return value
if ast.is_String() : if ast.is_String() :
return ast.string() return ast.string()
return String( eval_Numeric(ast) )
var msgT = "eval - Unimplemented: {ast}"
var msg = msgT.format({"ast" : JSON.print(ast.to_SExpression(), "\t") })
throw(msg)
func eval_Numeric( ast ):
if ast.is_Number() :
return float(ast.arg(1))
if ast.type() == NType.op_Add: if ast.type() == NType.op_Add:
return String(eval( ast.arg(1) ) + eval( ast.arg(2) )) var result = 0.0; var index = 1
while index <= ast.num_args():
result += eval_Numeric( ast.arg(index) )
index += 1
return result
if ast.type() == NType.op_Sub:
var result = 0.0; var index = 1
while index <= ast.num_args():
result -= eval_Numeric( ast.arg(index) )
index += 1
return result
if ast.type() == NType.op_Mult: if ast.type() == NType.op_Mult:
return String(eval( ast.arg(1) ) * eval( ast.arg(2) )) var result = 1.0; var index = 1
while index <= ast.num_args():
result *= eval_Numeric( ast.arg(index) )
index += 1
return result
if ast.type() == NType.op_Div:
var result = 1.0; var index = 1
while index <= ast.num_args():
result /= eval_Numeric( ast.arg(index) )
result += 1
return result
throw("Unimplemented")

View File

@ -127,9 +127,9 @@ const Spec : Dictionary = \
TokenType.op_LNot : "^!", TokenType.op_LNot : "^!",
# Arithmetic # Arithmetic
TokenType.op_CAssign : "^[\\*\\/+-]=", TokenType.op_CAssign : "^[\\*\\/+\\-]=",
TokenType.op_Assign : "^=", TokenType.op_Assign : "^=",
TokenType.op_Additive : "^[+-]", TokenType.op_Additive : "^[+\\-]",
TokenType.op_Multiplicative : "^[\\*\\/]", TokenType.op_Multiplicative : "^[\\*\\/]",
# Literals # Literals
@ -231,7 +231,7 @@ func compile_regex():
regex = RegEx.new() regex = RegEx.new()
var original = Spec[type] var original = Spec[type]
var transpiled = SRegEx.transpile(SSpec[type]) var transpiled = SRegEx.compile(SSpec[type])
assert(transpiled == original, "transpiled did not match original") assert(transpiled == original, "transpiled did not match original")

View File

@ -1035,7 +1035,6 @@ func parse_StringLiteral():
return node return node
# > Literal # > Literal
# BooleanLiteral # BooleanLiteral
# : true # : true

View File

@ -664,7 +664,7 @@ func parse_GlyphDash():
var \ var \
node = ASTNode.new() node = ASTNode.new()
node.Type = NodeType.glyph node.Type = NodeType.glyph
node.Value = "-" node.Value = "\\-"
return node return node
@ -894,22 +894,21 @@ func parse_String():
var ExprAST : ASTNode var ExprAST : ASTNode
var RegexResult : String var RegexResult : String
func transpile(expression : String): func compile(expression : String):
init( expression ) init( expression )
NextToken = next_Token() NextToken = next_Token()
ExprAST = parse_OpUnion(null) ExprAST = parse_OpUnion(null)
return transiple_Union(ExprAST) return compile_Union(ExprAST)
func transiple_Union(node : ASTNode): func compile_Union(node : ASTNode):
var result = "" var result = ""
var expressionLeft = node.Value var expressionLeft = node.Value
if node.Type == NodeType.union : if node.Type == NodeType.union :
expressionLeft = node.Value[0].Value expressionLeft = node.Value[0].Value
for entry in expressionLeft : for entry in expressionLeft :
match entry.Type : match entry.Type :
NodeType.str_start: NodeType.str_start:
@ -918,15 +917,15 @@ func transiple_Union(node : ASTNode):
result += "$" result += "$"
NodeType.capture: NodeType.capture:
result += transpile_CaptureGroup(entry, false) result += compile_CaptureGroup(entry, false)
NodeType.look: NodeType.look:
result += transpile_LookAhead(entry, false) result += compile_LookAhead(entry, false)
NodeType.ref: NodeType.ref:
result += transpile_Backreference(entry) result += compile_Backreference(entry)
NodeType.repeat: NodeType.repeat:
result += transpile_Repeat(entry) result += compile_Repeat(entry)
NodeType.set: NodeType.set:
result += transpile_Set(entry, false) result += compile_Set(entry, false)
NodeType.glyph: NodeType.glyph:
result += entry.Value result += entry.Value
@ -942,19 +941,18 @@ func transiple_Union(node : ASTNode):
result += entry.Value result += entry.Value
NodeType.string: NodeType.string:
result += transpile_String(entry, false) result += compile_String(entry, false)
NodeType.op_not: NodeType.op_not:
result += transpile_OpNot(entry) result += compile_OpNot(entry)
if node.Type == NodeType.union && node.Value[1] != null : if node.Type == NodeType.union && node.Value[1] != null :
result += "|" result += "|"
result += transiple_Union(node.Value[1]) result += compile_Union(node.Value[1])
return result return result
func transpile_CaptureGroup(node : ASTNode, negate : bool): func compile_CaptureGroup(node : ASTNode, negate : bool):
var result = "" var result = ""
if negate : if negate :
@ -962,12 +960,12 @@ func transpile_CaptureGroup(node : ASTNode, negate : bool):
else : else :
result += "(" result += "("
result += transiple_Union(node.Value) result += compile_Union(node.Value)
result += ")" result += ")"
return result return result
func transpile_LookAhead(node : ASTNode, negate : bool): func compile_LookAhead(node : ASTNode, negate : bool):
var result = "" var result = ""
if negate : if negate :
@ -975,19 +973,19 @@ func transpile_LookAhead(node : ASTNode, negate : bool):
else : else :
result += "(?=" result += "(?="
result += transiple_Union(node.Value.Value) result += compile_Union(node.Value.Value)
result += ")" result += ")"
return result return result
func transpile_Backreference(node : ASTNode): func compile_Backreference(node : ASTNode):
var \ var \
result = "\\" result = "\\"
result += node.Value result += node.Value
return result return result
func transpile_Repeat(node : ASTNode): func compile_Repeat(node : ASTNode):
var result = "" var result = ""
var vrange = node.Value[0] var vrange = node.Value[0]
var lazy = node.Value[1] var lazy = node.Value[1]
@ -1013,7 +1011,7 @@ func transpile_Repeat(node : ASTNode):
return result return result
func transpile_Set(node : ASTNode, negate : bool): func compile_Set(node : ASTNode, negate : bool):
var result = "" var result = ""
if negate : if negate :
@ -1023,7 +1021,7 @@ func transpile_Set(node : ASTNode, negate : bool):
for entry in node.Value : for entry in node.Value :
if entry.Type == NodeType.op_not : if entry.Type == NodeType.op_not :
result += transpile_OpNot(entry) result += compile_OpNot(entry)
elif entry.Type == NodeType.between : elif entry.Type == NodeType.between :
result += entry.Value[0].Value result += entry.Value[0].Value
result += "-" result += "-"
@ -1035,7 +1033,7 @@ func transpile_Set(node : ASTNode, negate : bool):
return result return result
func transpile_String(node : ASTNode, negate : bool): func compile_String(node : ASTNode, negate : bool):
var result = "" var result = ""
if negate : if negate :
@ -1052,14 +1050,14 @@ func transpile_String(node : ASTNode, negate : bool):
return result return result
func transpile_OpNot(node : ASTNode): func compile_OpNot(node : ASTNode):
var result = "" var result = ""
var entry = node.Value var entry = node.Value
match entry.Type : match entry.Type :
NodeType.capture: NodeType.capture:
result += transpile_CaptureGroup(entry, true) result += compile_CaptureGroup(entry, true)
NodeType.digit: NodeType.digit:
result += "\\D" result += "\\D"
NodeType.word: NodeType.word:
@ -1067,10 +1065,10 @@ func transpile_OpNot(node : ASTNode):
NodeType.whitespace: NodeType.whitespace:
result += "\\S" result += "\\S"
NodeType.look: NodeType.look:
result += transpile_LookAhead(entry, true) result += compile_LookAhead(entry, true)
NodeType.string: NodeType.string:
result += transpile_String(entry, true) result += compile_String(entry, true)
NodeType.set: NodeType.set:
result += transpile_Set(entry, true) result += compile_Set(entry, true)
return result return result

View File

@ -41,4 +41,6 @@ if not exist Engine\gd\bin\godot.windows.opt.64.exe (
goto :opt_wait goto :opt_wait
) )
timeout 2
start /w build_project.bat start /w build_project.bat