Created
March 10, 2022 03:32
-
-
Save tangentstorm/bd9c27c45aff04a43050091003e1f4be to your computer and use it in GitHub Desktop.
simple command language parser for jprez in gdscript (godot).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# i wrote this, and it works, but then i decided to just use Godot's own Expression parser. | |
# https://docs.godotengine.org/en/latest/tutorials/scripting/evaluating_expressions.html | |
func _examples(): | |
test('@title["the deck"]') | |
test('@show["jp-editor"; 0]') | |
test('@ed.xy[ 0 5]') | |
func test(cmd:String): | |
if cmd.begins_with('@'): | |
print(cmd) | |
cmd = cmd.right(1) | |
var e = EventParser.new() | |
var toks = e.scan(cmd) | |
print(toks) | |
var ast = e.parse(cmd) | |
print(ast) | |
else: print("bad command: %s" % cmd) | |
class EventParser: | |
enum TOK { SPACE, LBRACK, RBRACK, SEMI, NUMS, STR, NAME, END } | |
const RX = '(?<skip>\\s+)|\\[|\\]|;|(\\d+(\\s+\\d+))|"([^"]|[\\\\]\\")*"|(\\.|\\w)+' | |
var rxToken:RegEx | |
var tokens: Array # array of tokens | |
var ii: int # counter | |
var tt: int # current token type | |
func _init(): | |
rxToken = RegEx.new(); rxToken.compile(RX) | |
func tok_type(tok:String): | |
match tok[0]: | |
' ': return TOK.SPACE | |
'[': return TOK.LBRACK | |
']': return TOK.RBRACK | |
';': return TOK.SEMI | |
'"': return TOK.STR | |
'0','1','2','3','4','5','6','7','8','9': return TOK.NUMS | |
_: return TOK.NAME | |
func scan(cmd:String): | |
var toks = [] | |
for m in rxToken.search_all(cmd): | |
if m.get_string("skip"): continue # drop spaces | |
toks.push_back(m.get_string()) | |
return toks | |
func parse(cmd:String): | |
ii = 0; tokens = scan(cmd) | |
return _parse_call() | |
func _tt(): | |
if ii >= len(tokens): return TOK.END | |
tt=tok_type(tokens[ii]) | |
return tt | |
func _expected_msg(kinds:Array)->String: | |
var res = '' | |
if kinds: | |
for k in kinds: res += ' | ' + TOK.keys()[k] | |
res = res.right(3) | |
return res | |
func _expect(kinds:Array): | |
if ii >= len(tokens): | |
printerr('unexpected end of input. expecting ', _expected_msg(kinds)) | |
else: | |
var tt = tok_type(tokens[ii]) | |
if tt in kinds: return tokens[ii] | |
else: | |
var tk = TOK.keys() | |
printerr('error: expecting %s but got %s (%s)' % [_expected_msg(kinds), tk[tt], tokens[ii]]) | |
func _take(kinds:Array): | |
var res = _expect(kinds) | |
ii += 1 | |
return res | |
func _parse_call(): | |
var ident = _take([TOK.NAME]) | |
_take([TOK.LBRACK]) | |
var args = [] | |
while _tt() != TOK.RBRACK: | |
match tt: | |
TOK.STR: | |
# !! be lazv and borrow godot's string parser | |
var e = Expression.new() | |
assert(OK==e.parse(tokens[ii]), "bad string: %s" % tokens[ii]) | |
args.push_back(e.execute()) | |
TOK.NUMS: | |
var nums = tokens[ii].split_floats(' ') | |
args.push_back(nums[0] if len(nums)==1 else nums) | |
_: assert(false, "unexpected %s inside a call!" % TOK.keys()[tt]) | |
ii += 1 | |
if _expect([TOK.RBRACK, TOK.SEMI]) == ';': ii+=1 | |
return [ident, args] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment