compiler_wip.gd
· 2.7 KiB · GDScript3
Неформатований
Playground
extends RefCounted
class_name NovaCompiler
# NOTE: Godot's docs for array states that `.resize` + direct assignment is faster
# than repeatedly calling `append` and `push_back`.
static var prelude = """
extends RefCounted
var state = %s
func push(stack_symbol, symbol) -> void:
state[stack_symbol].push_back(symbol)
func peek(stack_symbol, depth : int, symbol) -> bool:
var stack = state[stack_symbol]
if not stack: return false
return stack[stack.size() - depth] == symbol
func pop(stack_symbol) -> void:
state[stack_symbol].pop_back()
"""
static func compile(json_string: String) -> GDScript:
var json = JSON.new()
var error = json.parse(json_string)
if error != OK:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
return GDScript.new()
var rules = json.data.rules
var state = json.data.state
var compiled_rules := PackedStringArray([prelude % state])
var i := 0
for rule in rules:
var conditions = rule.conditions
var results = rule.results
compiled_rules.push_back("func _rule_%d() -> bool:" % i)
var depths : Dictionary[String, int] = {}
for condition in conditions:
for action in condition.pattern:
match action.type:
"variable":
# TODO: name mangle this
compiled_rules.push_back("\tvar %s" % action.symbol)
for condition in conditions:
var stack : String = condition.stack.c_escape()
for action in condition.pattern:
var depth = depths.get_or_add(stack, 0)
depths[stack] = depth + 1
match action.type:
"literal":
compiled_rules.push_back("\tif not peek(\"%s\", %d, \"%s\"): return false" % [
stack,
depth,
action.symbol.c_escape()
])
"variable":
compiled_rules.push_back("\tif %s == null and peek(\"%s\", %d, \"%s\"): return false" % [
action.symbol.c_escape(),
stack,
depth,
action.symbol.c_escape()
])
compiled_rules.push_back("\t%s = peek(\"%s\", %d, \"%s\")" % [
action.symbol.c_escape(),
stack,
depth,
action.symbol.c_escape()
])
for condition in conditions:
var stack : String = condition.stack.c_escape()
for __ in range(condition.pattern.size()):
compiled_rules.push_back("\tpop(\"%s\")" % stack)
for result in results:
var stack : String = result.stack
for action in result.pattern:
match action.type:
"literal":
compiled_rules.push_back("\tpush(\"%s\", \"%s\")" % [
stack, action.symbol.c_escape()
])
"variable":
compiled_rules.push_back("\tpush(\"%s\", %s if %s else \"%s\")" % [
stack, action.symbol, action.symbol, action.symbol.c_escape()
])
pass
print(conditions)
print(results)
print("\n".join(compiled_rules))
return GDScript.new()
| 1 | extends RefCounted |
| 2 | class_name NovaCompiler |
| 3 | # NOTE: Godot's docs for array states that `.resize` + direct assignment is faster |
| 4 | # than repeatedly calling `append` and `push_back`. |
| 5 | static var prelude = """ |
| 6 | extends RefCounted |
| 7 | |
| 8 | var state = %s |
| 9 | |
| 10 | func push(stack_symbol, symbol) -> void: |
| 11 | state[stack_symbol].push_back(symbol) |
| 12 | |
| 13 | func peek(stack_symbol, depth : int, symbol) -> bool: |
| 14 | var stack = state[stack_symbol] |
| 15 | if not stack: return false |
| 16 | return stack[stack.size() - depth] == symbol |
| 17 | |
| 18 | func pop(stack_symbol) -> void: |
| 19 | state[stack_symbol].pop_back() |
| 20 | """ |
| 21 | |
| 22 | static func compile(json_string: String) -> GDScript: |
| 23 | var json = JSON.new() |
| 24 | var error = json.parse(json_string) |
| 25 | if error != OK: |
| 26 | print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) |
| 27 | return GDScript.new() |
| 28 | |
| 29 | var rules = json.data.rules |
| 30 | var state = json.data.state |
| 31 | |
| 32 | var compiled_rules := PackedStringArray([prelude % state]) |
| 33 | var i := 0 |
| 34 | |
| 35 | for rule in rules: |
| 36 | var conditions = rule.conditions |
| 37 | var results = rule.results |
| 38 | compiled_rules.push_back("func _rule_%d() -> bool:" % i) |
| 39 | var depths : Dictionary[String, int] = {} |
| 40 | for condition in conditions: |
| 41 | for action in condition.pattern: |
| 42 | match action.type: |
| 43 | "variable": |
| 44 | # TODO: name mangle this |
| 45 | compiled_rules.push_back("\tvar %s" % action.symbol) |
| 46 | for condition in conditions: |
| 47 | var stack : String = condition.stack.c_escape() |
| 48 | for action in condition.pattern: |
| 49 | var depth = depths.get_or_add(stack, 0) |
| 50 | depths[stack] = depth + 1 |
| 51 | match action.type: |
| 52 | "literal": |
| 53 | compiled_rules.push_back("\tif not peek(\"%s\", %d, \"%s\"): return false" % [ |
| 54 | stack, |
| 55 | depth, |
| 56 | action.symbol.c_escape() |
| 57 | ]) |
| 58 | "variable": |
| 59 | compiled_rules.push_back("\tif %s == null and peek(\"%s\", %d, \"%s\"): return false" % [ |
| 60 | action.symbol.c_escape(), |
| 61 | stack, |
| 62 | depth, |
| 63 | action.symbol.c_escape() |
| 64 | ]) |
| 65 | compiled_rules.push_back("\t%s = peek(\"%s\", %d, \"%s\")" % [ |
| 66 | action.symbol.c_escape(), |
| 67 | stack, |
| 68 | depth, |
| 69 | action.symbol.c_escape() |
| 70 | ]) |
| 71 | for condition in conditions: |
| 72 | var stack : String = condition.stack.c_escape() |
| 73 | for __ in range(condition.pattern.size()): |
| 74 | compiled_rules.push_back("\tpop(\"%s\")" % stack) |
| 75 | for result in results: |
| 76 | var stack : String = result.stack |
| 77 | for action in result.pattern: |
| 78 | match action.type: |
| 79 | "literal": |
| 80 | compiled_rules.push_back("\tpush(\"%s\", \"%s\")" % [ |
| 81 | stack, action.symbol.c_escape() |
| 82 | ]) |
| 83 | "variable": |
| 84 | compiled_rules.push_back("\tpush(\"%s\", %s if %s else \"%s\")" % [ |
| 85 | stack, action.symbol, action.symbol, action.symbol.c_escape() |
| 86 | ]) |
| 87 | pass |
| 88 | print(conditions) |
| 89 | print(results) |
| 90 | print("\n".join(compiled_rules)) |
| 91 | |
| 92 | return GDScript.new() |
| 93 |
progress.gd
· 740 B · GDScript3
Неформатований
Playground
extends RefCounted
var state = { "foo": ["foo", "bar", "baz", "quux"], "bar": ["quux", "baz", "bar", "foo"] }
func push(stack_symbol, symbol) -> void:
state[stack_symbol].push_back(symbol)
func peek(stack_symbol, depth : int, symbol) -> bool:
var stack = state[stack_symbol]
if not stack: return false
return stack[stack.size() - depth] == symbol
func pop(stack_symbol) -> void:
state[stack_symbol].pop_back()
func _rule_0() -> bool:
var baz
if not peek("foo", 0, "bar"): return false
if baz == null and peek("foo", 1, "baz"): return false
baz = peek("foo", 1, "baz")
if not peek("foo", 2, "bin"): return false
pop("foo")
pop("foo")
pop("foo")
push("bar", "quux")
push("bar", baz if baz else "baz")
push("bar", "quin")
| 1 | extends RefCounted |
| 2 | |
| 3 | var state = { "foo": ["foo", "bar", "baz", "quux"], "bar": ["quux", "baz", "bar", "foo"] } |
| 4 | |
| 5 | func push(stack_symbol, symbol) -> void: |
| 6 | state[stack_symbol].push_back(symbol) |
| 7 | |
| 8 | func peek(stack_symbol, depth : int, symbol) -> bool: |
| 9 | var stack = state[stack_symbol] |
| 10 | if not stack: return false |
| 11 | return stack[stack.size() - depth] == symbol |
| 12 | |
| 13 | func pop(stack_symbol) -> void: |
| 14 | state[stack_symbol].pop_back() |
| 15 | |
| 16 | func _rule_0() -> bool: |
| 17 | var baz |
| 18 | if not peek("foo", 0, "bar"): return false |
| 19 | if baz == null and peek("foo", 1, "baz"): return false |
| 20 | baz = peek("foo", 1, "baz") |
| 21 | if not peek("foo", 2, "bin"): return false |
| 22 | pop("foo") |
| 23 | pop("foo") |
| 24 | pop("foo") |
| 25 | push("bar", "quux") |
| 26 | push("bar", baz if baz else "baz") |
| 27 | push("bar", "quin") |
| 28 |