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.
|
||||
|
||||
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).
|
||||
|
||||
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
|
||||
|
||||
`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.
|
||||
|
||||
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
|
||||
|
||||
`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 **MUST** guarantee unique token symbol. The processor **SHOULD**
|
||||
-> e.g. if collision, append "_<2 bytes hex rand>"
|
||||
`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. 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`).
|
||||
|
||||
@ -53,14 +56,14 @@ The command processor **SHOULD** store the executing key as the "owner" of the v
|
||||
|
||||
### 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.
|
||||
|
||||
|
||||
### 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
|
||||
@ -82,3 +85,12 @@ Continue after execution, regardless of result.
|
||||
`NEED <id | ->`
|
||||
|
||||
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