Add lexer/parser
This commit is contained in:
parent
7937eb5187
commit
7a475d1a9f
32
README.md
32
README.md
@ -20,29 +20,32 @@ Ids are strings. Uuid strings are preferred.
|
|||||||
|
|
||||||
The command processor **MUST** ensure that all ids are unique.
|
The command processor **MUST** ensure that all ids are unique.
|
||||||
|
|
||||||
If `-` is supplied as `id`, a unique, random (uuid4) id will be generated.
|
If `-` is supplied as `id`, a unique, random (uuid4) id **MUST** be generated. All commands return the (given or generated) id.
|
||||||
|
|
||||||
All state change commands must implement a success or fail state, that may be used for the control commands (see below).
|
All state change commands must implement a success or fail state, that may be used for the control commands (see below).
|
||||||
|
|
||||||
Actions depending on other created assets (keys, vouchers) that have failed to execution **MUST** abort further execution and raise exception.
|
Further execution **MUST** aborted and exception **MUST** be raised if:
|
||||||
|
|
||||||
|
* Actions depending on other created assets (keys, vouchers) that have failed to execute
|
||||||
|
* A store cannot handle a command (e.g. the custodial store may not handle voucher creation)
|
||||||
|
|
||||||
|
|
||||||
### Create a new key
|
### Create a new key
|
||||||
|
|
||||||
`KEY_CREATE <id | "-"> <string:key_name> <string:store_name> -> hex:wallet_address`
|
`KEY_CREATE <id | "-"> <string:key_name> <string:store_name> [hex:private_key] -> id`
|
||||||
|
|
||||||
The initial use-case for the `store` is to choose between custodial system and independent keystore (simulating sovereign key holders). Future use-cases may need to use other stores aswell.
|
The initial use-case for the `store` is to choose between custodial system and independent keystore (simulating sovereign key holders). Future use-cases may need to use other stores aswell (e.g. a HTTP service that stores keystore files for given private keys).
|
||||||
|
|
||||||
The `key_name` or the returned `address` may be used to refer to the key after the command is executed.
|
The `key_name` or the returned `address` may be used to refer to the key after the command is executed.
|
||||||
|
|
||||||
|
Further execution **MUST** aborted and exception **MUST** be raised if private key is given and the store cannot store provided private keys.
|
||||||
|
|
||||||
|
|
||||||
### Create a new voucher
|
### Create a new voucher
|
||||||
|
|
||||||
`VOUCHER_CREATE <id | "-"> <string:voucher_symbol> <string:voucher_name> <int:decimals> [<int:decay_factor> <int:decay_period> [hex:sink_address]] -> hex:contract_address`
|
`VOUCHER_CREATE <id | "-"> <string:voucher_symbol> <string:voucher_name> <int:decimals> [<int:decay_factor> <int:decay_period> [hex:sink_address]] -> id`
|
||||||
|
|
||||||
Voucher create **MUST** guarantee unique token symbol. The processor **SHOULD**
|
|
||||||
-> e.g. if collision, append "_<2 bytes hex rand>"
|
|
||||||
|
|
||||||
|
Voucher create **MUST** guarantee unique token symbol. If the requested symbol is already in use, the processor **SHOULD** try to append random ascii data to the symbol and try again until success.
|
||||||
|
|
||||||
The "decay" parameters specify that a contract with demurrage features must be used. If `sink_address` is not set, it defaults to the burn address (`0x000000000000000000000000000000000000dEaD`).
|
The "decay" parameters specify that a contract with demurrage features must be used. If `sink_address` is not set, it defaults to the burn address (`0x000000000000000000000000000000000000dEaD`).
|
||||||
|
|
||||||
@ -53,14 +56,14 @@ The command processor **SHOULD** store the executing key as the "owner" of the v
|
|||||||
|
|
||||||
### Mint vouchers
|
### Mint vouchers
|
||||||
|
|
||||||
`VOUCHER_MINT <id | "-"> <string:voucher_symbol | hex:voucher_address> <int:amount> [<to_account | to_key_name>] -> hex:to_account`
|
`VOUCHER_MINT <id | "-"> <string:voucher_symbol | hex:voucher_address> <int:amount> [<to_account | to_key_name>] -> id`
|
||||||
|
|
||||||
If `to_*` is not specified, the recipient should be the owner of the voucher.
|
If `to_*` is not specified, the recipient should be the owner of the voucher.
|
||||||
|
|
||||||
|
|
||||||
### Transfer vouchers
|
### Transfer vouchers
|
||||||
|
|
||||||
`VOUCHER_TRANSFER <id | "-"> <voucher_symbol | voucher_address> <amount> <to_account | to_key_name> <from_account | from_key_name > -> hex:from_account`
|
`VOUCHER_TRANSFER <id | "-"> <voucher_symbol | voucher_address> <amount> <to_account | to_key_name> <from_account | from_key_name > id`
|
||||||
|
|
||||||
|
|
||||||
## Control commands
|
## Control commands
|
||||||
@ -82,3 +85,12 @@ Continue after execution, regardless of result.
|
|||||||
`NEED <id | ->`
|
`NEED <id | ->`
|
||||||
|
|
||||||
Continue after execution, but raise exception and abort execution if any of the commands fail.
|
Continue after execution, but raise exception and abort execution if any of the commands fail.
|
||||||
|
|
||||||
|
|
||||||
|
## Report commands
|
||||||
|
|
||||||
|
In the event that an interactive tool would be implemented for the protocol, some assistance for puny humans would be required aswell.
|
||||||
|
|
||||||
|
`PEEK <id>`
|
||||||
|
|
||||||
|
Return human-readable version of the issued command, its current state, and its associated data (e.g. wallet address, contract address).
|
||||||
|
249
parse.py
Normal file
249
parse.py
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
import ply.lex as lex
|
||||||
|
import ply.yacc as yacc
|
||||||
|
import enum
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
tokens = (
|
||||||
|
'ID',
|
||||||
|
'NOID',
|
||||||
|
'HEX',
|
||||||
|
'LABEL',
|
||||||
|
'VALUE',
|
||||||
|
'END',
|
||||||
|
)
|
||||||
|
|
||||||
|
t_ID = r'[a-zA-Z0-9]+(-[a-zA-Z0-9]+)+'
|
||||||
|
t_NOID = r'\-'
|
||||||
|
t_LABEL = r'[a-zA-Z_]+'
|
||||||
|
t_VALUE = r'\d+'
|
||||||
|
t_END = r'\n'
|
||||||
|
t_HEX = r'0x([a-fA-F0-9])+'
|
||||||
|
|
||||||
|
#def t_VALUE(t):
|
||||||
|
# r'\d+'
|
||||||
|
# t.value = int(t.value)
|
||||||
|
|
||||||
|
#def t_HEX(t):
|
||||||
|
# r'0x([a-fA-F0-9])+'
|
||||||
|
#print(t)
|
||||||
|
#try:
|
||||||
|
# t.value = bytes.fromhex(t.value)
|
||||||
|
#except:
|
||||||
|
# return False
|
||||||
|
#return t.value
|
||||||
|
#t.value = t.value
|
||||||
|
# pass
|
||||||
|
|
||||||
|
t_ignore = ' \t'
|
||||||
|
|
||||||
|
def t_error(t):
|
||||||
|
print("problem: ", t.value[0])
|
||||||
|
t.lexer.skip(1)
|
||||||
|
|
||||||
|
lexer = lex.lex()
|
||||||
|
#
|
||||||
|
#data = '''
|
||||||
|
#FOOBAR uf-2etg 0xa3bdefa momo 123
|
||||||
|
#
|
||||||
|
#BARBAR
|
||||||
|
#BAZ
|
||||||
|
#
|
||||||
|
#BASFB foo-bar-baz
|
||||||
|
#'''
|
||||||
|
#
|
||||||
|
#lexer.input(data)
|
||||||
|
#
|
||||||
|
#while True:
|
||||||
|
# tok = lexer.token()
|
||||||
|
# if not tok:
|
||||||
|
# break
|
||||||
|
# print(tok)
|
||||||
|
|
||||||
|
|
||||||
|
class CmdId(enum.IntEnum):
|
||||||
|
KEY_CREATE = 0x1
|
||||||
|
VOUCHER_CREATE = 0x10
|
||||||
|
VOUCHER_MINT = 0x11
|
||||||
|
VOUCHER_TRANSFER = 0x12
|
||||||
|
WAIT = 0x20
|
||||||
|
NEED = 0x21
|
||||||
|
PEEK = 0x80
|
||||||
|
|
||||||
|
|
||||||
|
class Agent:
|
||||||
|
def __str__(self):
|
||||||
|
return self.__class__.__name__ + ':' #{}'.format(self.__class__.__name__, self.v)
|
||||||
|
|
||||||
|
|
||||||
|
class AddressAgent(Agent):
|
||||||
|
def __init__(self, v):
|
||||||
|
self.v = bytes.fromhex(v[2:])
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return Agent.__str__(self) + self.v.hex()
|
||||||
|
|
||||||
|
|
||||||
|
class NameAgent(Agent):
|
||||||
|
def __init__(self, v):
|
||||||
|
self.v = v
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return Agent.__str__(self) + self.v
|
||||||
|
|
||||||
|
class Cmd:
|
||||||
|
|
||||||
|
def __init__(self, cmd):
|
||||||
|
self.c = CmdId[cmd]
|
||||||
|
self.i = None
|
||||||
|
self.a = None
|
||||||
|
self.f = None
|
||||||
|
self.t = None
|
||||||
|
self.v = 0
|
||||||
|
self.k = None
|
||||||
|
self.d = 0
|
||||||
|
self.p = 0
|
||||||
|
self.s = None
|
||||||
|
self.n = None
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "[{:02d}]{} i={} v={} a={} f={} t={} k={} d={} p={} s={} n={}".format(self.c, self.c.name, self.i, self.v, self.a, self.f, self.t, self.k, self.d, self.p, self.s, self.n)
|
||||||
|
|
||||||
|
|
||||||
|
def to_store(v):
|
||||||
|
return str(v)
|
||||||
|
|
||||||
|
|
||||||
|
def to_agent(v):
|
||||||
|
r = None
|
||||||
|
try:
|
||||||
|
r = AddressAgent(v)
|
||||||
|
except ValueError:
|
||||||
|
r = NameAgent(v)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def p_cmd(p):
|
||||||
|
'''cmd : key_create
|
||||||
|
| voucher_mint
|
||||||
|
| voucher_transfer
|
||||||
|
| voucher_create
|
||||||
|
| pair
|
||||||
|
'''
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
|
||||||
|
def p_key_create(p):
|
||||||
|
'''key_create : change_label LABEL LABEL
|
||||||
|
| change_label LABEL LABEL HEX
|
||||||
|
'''
|
||||||
|
o = p[1]
|
||||||
|
o.f = NameAgent(p[2])
|
||||||
|
o.t = to_store(p[3])
|
||||||
|
if len(p) > 4:
|
||||||
|
o.k = p[4]
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_voucher_mint(p):
|
||||||
|
'''voucher_mint : change_label hv
|
||||||
|
| change_label nv
|
||||||
|
'''
|
||||||
|
o = p[1]
|
||||||
|
if o.c.value & 0x10 == 0:
|
||||||
|
raise ValueError("not a voucher command")
|
||||||
|
o.v = int(p[2][1])
|
||||||
|
o.a = to_agent(p[2][0])
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_voucher_create(p):
|
||||||
|
'''voucher_create : change_label LABEL LABEL VALUE
|
||||||
|
| change_label LABEL LABEL VALUE VALUE VALUE
|
||||||
|
'''
|
||||||
|
o = p[1]
|
||||||
|
if o.c.value & 0x10 == 0:
|
||||||
|
raise ValueError("not a voucher command")
|
||||||
|
o.s = p[2]
|
||||||
|
o.n = p[3]
|
||||||
|
o.v = int(p[4])
|
||||||
|
if len(p) > 5:
|
||||||
|
o.d = p[5]
|
||||||
|
o.p = p[6]
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_voucher_mint_recipient(p):
|
||||||
|
'''voucher_mint : change_label hv HEX
|
||||||
|
| change_label nv HEX
|
||||||
|
| change_label hv LABEL
|
||||||
|
| change_label nv LABEL
|
||||||
|
'''
|
||||||
|
o = p[1]
|
||||||
|
if o.c.value & 0x10 == 0:
|
||||||
|
raise ValueError("not a voucher command")
|
||||||
|
o.v = int(p[2][1])
|
||||||
|
o.a = to_agent(p[2][0])
|
||||||
|
o.t = to_agent(p[3])
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_voucher_transfer(p):
|
||||||
|
'''voucher_transfer : change_label hv HEX HEX
|
||||||
|
| change_label nv HEX HEX
|
||||||
|
| change_label hv LABEL HEX
|
||||||
|
| change_label nv LABEL HEX
|
||||||
|
'''
|
||||||
|
o = p[1]
|
||||||
|
if o.c.value & 0x10 == 0:
|
||||||
|
raise ValueError("not a voucher command")
|
||||||
|
o.v = int(p[2][1])
|
||||||
|
o.a = to_agent(p[2][0])
|
||||||
|
o.t = to_agent(p[3])
|
||||||
|
o.f = to_agent(p[4])
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_nv(p):
|
||||||
|
'nv : LABEL VALUE'
|
||||||
|
p[0] = (p[1], p[2],)
|
||||||
|
|
||||||
|
|
||||||
|
def p_hv(p):
|
||||||
|
'hv : HEX VALUE'
|
||||||
|
p[0] = (p[1], p[2],)
|
||||||
|
|
||||||
|
|
||||||
|
def p_change_label(p):
|
||||||
|
'''change_label : pair
|
||||||
|
| pairnoid
|
||||||
|
'''
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
|
||||||
|
def p_pair(p):
|
||||||
|
'pair : LABEL ID'
|
||||||
|
o = Cmd(p[1])
|
||||||
|
o.i = p[2]
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
def p_pairnoid(p):
|
||||||
|
'pairnoid : LABEL NOID'
|
||||||
|
o = Cmd(p[1])
|
||||||
|
o.i = str(uuid.uuid4())
|
||||||
|
p[0] = o
|
||||||
|
|
||||||
|
|
||||||
|
parser = yacc.yacc()
|
||||||
|
|
||||||
|
print("result: {}".format(parser.parse("WAIT bar-baz")))
|
||||||
|
print("result: {}".format(parser.parse("KEY_CREATE bar-baz Foo BAr")))
|
||||||
|
print("result: {}".format(parser.parse("KEY_CREATE bar-baz Foo BAr 0xabcdef0")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_MINT - 0xdeadbeef 13 0xfdaf")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_MINT bar-baz 0xdeadbeef 13 0xfdaf")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_MINT bar-baz 0xdeadbeef 42")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_CREATE bar-baz Foo Bar 42")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_CREATE bar-baz Foo Bar 42 44 233")))
|
||||||
|
print("result: {}".format(parser.parse("VOUCHER_TRANSFER bar-baz 0xbeeffeed0123 666 foo 0x0fdc")))
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
ply==3.11
|
Loading…
Reference in New Issue
Block a user