Generalize live field bindings and use them for Studio canvas gestures
This commit is contained in:
@@ -106,7 +106,7 @@ operationMember
|
|||||||
;
|
;
|
||||||
|
|
||||||
valueMember
|
valueMember
|
||||||
: queryReadContract? VALUE identifier ID stringLiteral COLON valueType
|
: queryReadContract? (VALUE | FIELD) identifier ID stringLiteral COLON valueType
|
||||||
LBRACE valueMemberOperation* RBRACE
|
LBRACE valueMemberOperation* RBRACE
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -568,6 +568,7 @@ INTERFACE: 'interface';
|
|||||||
INTERFACES: 'interfaces';
|
INTERFACES: 'interfaces';
|
||||||
PACKAGE: 'package';
|
PACKAGE: 'package';
|
||||||
VALUE: 'value';
|
VALUE: 'value';
|
||||||
|
FIELD: 'field';
|
||||||
RELATION: 'relation';
|
RELATION: 'relation';
|
||||||
OPERATION: 'operation';
|
OPERATION: 'operation';
|
||||||
FUNCTION: 'function';
|
FUNCTION: 'function';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -47,112 +47,113 @@ INTERFACE=46
|
|||||||
INTERFACES=47
|
INTERFACES=47
|
||||||
PACKAGE=48
|
PACKAGE=48
|
||||||
VALUE=49
|
VALUE=49
|
||||||
RELATION=50
|
FIELD=50
|
||||||
OPERATION=51
|
RELATION=51
|
||||||
FUNCTION=52
|
OPERATION=52
|
||||||
CONSTRUCTOR=53
|
FUNCTION=53
|
||||||
CONSTRUCTS=54
|
CONSTRUCTOR=54
|
||||||
INPUT=55
|
CONSTRUCTS=55
|
||||||
CONFORM=56
|
INPUT=56
|
||||||
AS=57
|
CONFORM=57
|
||||||
BIND=58
|
AS=58
|
||||||
STATIC=59
|
BIND=59
|
||||||
TO=60
|
STATIC=60
|
||||||
PRIVATE=61
|
TO=61
|
||||||
SHARED=62
|
PRIVATE=62
|
||||||
STATE=63
|
SHARED=63
|
||||||
EDGE=64
|
STATE=64
|
||||||
PROJECTION=65
|
EDGE=65
|
||||||
WITH=66
|
PROJECTION=66
|
||||||
USING=67
|
WITH=67
|
||||||
ACCEPT=68
|
USING=68
|
||||||
VIA=69
|
ACCEPT=69
|
||||||
MATERIALIZE=70
|
VIA=70
|
||||||
IF=71
|
MATERIALIZE=71
|
||||||
ABSENT=72
|
IF=72
|
||||||
ON=73
|
ABSENT=73
|
||||||
POLICY=74
|
ON=74
|
||||||
DEFAULT=75
|
POLICY=75
|
||||||
SOURCE=76
|
DEFAULT=76
|
||||||
REPOSITORY=77
|
SOURCE=77
|
||||||
COMMIT=78
|
REPOSITORY=78
|
||||||
REVISION=79
|
COMMIT=79
|
||||||
SEMANTIC_MAJOR=80
|
REVISION=80
|
||||||
ON_DELETE=81
|
SEMANTIC_MAJOR=81
|
||||||
LIFECYCLE=82
|
ON_DELETE=82
|
||||||
RETAIN_OTHER=83
|
LIFECYCLE=83
|
||||||
KEYED=84
|
RETAIN_OTHER=84
|
||||||
PUBLIC_TRAVERSAL=85
|
KEYED=85
|
||||||
ID=86
|
PUBLIC_TRAVERSAL=86
|
||||||
DOC=87
|
ID=87
|
||||||
MODE=88
|
DOC=88
|
||||||
EMITS=89
|
MODE=89
|
||||||
RECEIVER=90
|
EMITS=90
|
||||||
REQUIRES=91
|
RECEIVER=91
|
||||||
ANY=92
|
REQUIRES=92
|
||||||
GET=93
|
ANY=93
|
||||||
SET=94
|
GET=94
|
||||||
WATCH=95
|
SET=95
|
||||||
START=96
|
WATCH=96
|
||||||
STOP=97
|
START=97
|
||||||
READ=98
|
STOP=98
|
||||||
WRITE=99
|
READ=99
|
||||||
RESOLVE=100
|
WRITE=100
|
||||||
CONNECT=101
|
RESOLVE=101
|
||||||
DISCONNECT=102
|
CONNECT=102
|
||||||
CALL=103
|
DISCONNECT=103
|
||||||
WATCH_START=104
|
CALL=104
|
||||||
WATCH_STOP=105
|
WATCH_START=105
|
||||||
SUBSCRIBE=106
|
WATCH_STOP=106
|
||||||
UNSUBSCRIBE=107
|
SUBSCRIBE=107
|
||||||
REGISTER=108
|
UNSUBSCRIBE=108
|
||||||
CRDT=109
|
REGISTER=109
|
||||||
OPTIONAL_ONE=110
|
CRDT=110
|
||||||
EXACTLY_ONE=111
|
OPTIONAL_ONE=111
|
||||||
MANY_UNIQUE=112
|
EXACTLY_ONE=112
|
||||||
MANY=113
|
MANY_UNIQUE=113
|
||||||
ORDERED=114
|
MANY=114
|
||||||
UNIT=115
|
ORDERED=115
|
||||||
WATCH_HANDLE=116
|
UNIT=116
|
||||||
MESSAGE=117
|
WATCH_HANDLE=117
|
||||||
ATOM_REF=118
|
MESSAGE=118
|
||||||
INTERFACE_REF=119
|
ATOM_REF=119
|
||||||
OPTIONAL=120
|
INTERFACE_REF=120
|
||||||
LIST=121
|
OPTIONAL=121
|
||||||
RECORD=122
|
LIST=122
|
||||||
BOOL=123
|
RECORD=123
|
||||||
BYTES=124
|
BOOL=124
|
||||||
DOUBLE=125
|
BYTES=125
|
||||||
INT32=126
|
DOUBLE=126
|
||||||
INT64=127
|
INT32=127
|
||||||
STRING=128
|
INT64=128
|
||||||
UINT32=129
|
STRING=129
|
||||||
UINT64=130
|
UINT32=130
|
||||||
TRUE=131
|
UINT64=131
|
||||||
FALSE=132
|
TRUE=132
|
||||||
NULL=133
|
FALSE=133
|
||||||
ARROW=134
|
NULL=134
|
||||||
COLON=135
|
ARROW=135
|
||||||
SEMI=136
|
COLON=136
|
||||||
COMMA=137
|
SEMI=137
|
||||||
DOT=138
|
COMMA=138
|
||||||
LBRACE=139
|
DOT=139
|
||||||
RBRACE=140
|
LBRACE=140
|
||||||
LBRACK=141
|
RBRACE=141
|
||||||
RBRACK=142
|
LBRACK=142
|
||||||
LPAREN=143
|
RBRACK=143
|
||||||
RPAREN=144
|
LPAREN=144
|
||||||
LT=145
|
RPAREN=145
|
||||||
GT=146
|
LT=146
|
||||||
AMP=147
|
GT=147
|
||||||
EQUAL=148
|
AMP=148
|
||||||
INTEGER=149
|
EQUAL=149
|
||||||
JSON_NUMBER=150
|
INTEGER=150
|
||||||
IDENTIFIER=151
|
JSON_NUMBER=151
|
||||||
STRING_LITERAL=152
|
IDENTIFIER=152
|
||||||
LINE_COMMENT=153
|
STRING_LITERAL=153
|
||||||
BLOCK_COMMENT=154
|
LINE_COMMENT=154
|
||||||
WS=155
|
BLOCK_COMMENT=155
|
||||||
|
WS=156
|
||||||
'edit'=1
|
'edit'=1
|
||||||
'module'=2
|
'module'=2
|
||||||
'contract'=3
|
'contract'=3
|
||||||
@@ -202,102 +203,103 @@ WS=155
|
|||||||
'interfaces'=47
|
'interfaces'=47
|
||||||
'package'=48
|
'package'=48
|
||||||
'value'=49
|
'value'=49
|
||||||
'relation'=50
|
'field'=50
|
||||||
'operation'=51
|
'relation'=51
|
||||||
'function'=52
|
'operation'=52
|
||||||
'constructor'=53
|
'function'=53
|
||||||
'constructs'=54
|
'constructor'=54
|
||||||
'input'=55
|
'constructs'=55
|
||||||
'conform'=56
|
'input'=56
|
||||||
'as'=57
|
'conform'=57
|
||||||
'bind'=58
|
'as'=58
|
||||||
'static'=59
|
'bind'=59
|
||||||
'to'=60
|
'static'=60
|
||||||
'private'=61
|
'to'=61
|
||||||
'shared'=62
|
'private'=62
|
||||||
'state'=63
|
'shared'=63
|
||||||
'edge'=64
|
'state'=64
|
||||||
'projection'=65
|
'edge'=65
|
||||||
'with'=66
|
'projection'=66
|
||||||
'using'=67
|
'with'=67
|
||||||
'accept'=68
|
'using'=68
|
||||||
'via'=69
|
'accept'=69
|
||||||
'materialize'=70
|
'via'=70
|
||||||
'if'=71
|
'materialize'=71
|
||||||
'absent'=72
|
'if'=72
|
||||||
'on'=73
|
'absent'=73
|
||||||
'policy'=74
|
'on'=74
|
||||||
'default'=75
|
'policy'=75
|
||||||
'source'=76
|
'default'=76
|
||||||
'repository'=77
|
'source'=77
|
||||||
'commit'=78
|
'repository'=78
|
||||||
'revision'=79
|
'commit'=79
|
||||||
'semantic-major'=80
|
'revision'=80
|
||||||
'on-delete'=81
|
'semantic-major'=81
|
||||||
'lifecycle'=82
|
'on-delete'=82
|
||||||
'retain-other'=83
|
'lifecycle'=83
|
||||||
'keyed'=84
|
'retain-other'=84
|
||||||
'public-traversal'=85
|
'keyed'=85
|
||||||
'id'=86
|
'public-traversal'=86
|
||||||
'doc'=87
|
'id'=87
|
||||||
'mode'=88
|
'doc'=88
|
||||||
'emits'=89
|
'mode'=89
|
||||||
'receiver'=90
|
'emits'=90
|
||||||
'requires'=91
|
'receiver'=91
|
||||||
'any'=92
|
'requires'=92
|
||||||
'get'=93
|
'any'=93
|
||||||
'set'=94
|
'get'=94
|
||||||
'watch'=95
|
'set'=95
|
||||||
'start'=96
|
'watch'=96
|
||||||
'stop'=97
|
'start'=97
|
||||||
'read'=98
|
'stop'=98
|
||||||
'write'=99
|
'read'=99
|
||||||
'resolve'=100
|
'write'=100
|
||||||
'connect'=101
|
'resolve'=101
|
||||||
'disconnect'=102
|
'connect'=102
|
||||||
'call'=103
|
'disconnect'=103
|
||||||
'watch-start'=104
|
'call'=104
|
||||||
'watch-stop'=105
|
'watch-start'=105
|
||||||
'subscribe'=106
|
'watch-stop'=106
|
||||||
'unsubscribe'=107
|
'subscribe'=107
|
||||||
'register'=108
|
'unsubscribe'=108
|
||||||
'crdt'=109
|
'register'=109
|
||||||
'optional-one'=110
|
'crdt'=110
|
||||||
'exactly-one'=111
|
'optional-one'=111
|
||||||
'many-unique'=112
|
'exactly-one'=112
|
||||||
'many'=113
|
'many-unique'=113
|
||||||
'ordered'=114
|
'many'=114
|
||||||
'unit'=115
|
'ordered'=115
|
||||||
'watch-handle'=116
|
'unit'=116
|
||||||
'message'=117
|
'watch-handle'=117
|
||||||
'atom-ref'=118
|
'message'=118
|
||||||
'interface-ref'=119
|
'atom-ref'=119
|
||||||
'optional'=120
|
'interface-ref'=120
|
||||||
'list'=121
|
'optional'=121
|
||||||
'record'=122
|
'list'=122
|
||||||
'bool'=123
|
'record'=123
|
||||||
'bytes'=124
|
'bool'=124
|
||||||
'double'=125
|
'bytes'=125
|
||||||
'int32'=126
|
'double'=126
|
||||||
'int64'=127
|
'int32'=127
|
||||||
'string'=128
|
'int64'=128
|
||||||
'uint32'=129
|
'string'=129
|
||||||
'uint64'=130
|
'uint32'=130
|
||||||
'true'=131
|
'uint64'=131
|
||||||
'false'=132
|
'true'=132
|
||||||
'null'=133
|
'false'=133
|
||||||
'->'=134
|
'null'=134
|
||||||
':'=135
|
'->'=135
|
||||||
';'=136
|
':'=136
|
||||||
','=137
|
';'=137
|
||||||
'.'=138
|
','=138
|
||||||
'{'=139
|
'.'=139
|
||||||
'}'=140
|
'{'=140
|
||||||
'['=141
|
'}'=141
|
||||||
']'=142
|
'['=142
|
||||||
'('=143
|
']'=143
|
||||||
')'=144
|
'('=144
|
||||||
'<'=145
|
')'=145
|
||||||
'>'=146
|
'<'=146
|
||||||
'&'=147
|
'>'=147
|
||||||
'='=148
|
'&'=148
|
||||||
|
'='=149
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -47,112 +47,113 @@ INTERFACE=46
|
|||||||
INTERFACES=47
|
INTERFACES=47
|
||||||
PACKAGE=48
|
PACKAGE=48
|
||||||
VALUE=49
|
VALUE=49
|
||||||
RELATION=50
|
FIELD=50
|
||||||
OPERATION=51
|
RELATION=51
|
||||||
FUNCTION=52
|
OPERATION=52
|
||||||
CONSTRUCTOR=53
|
FUNCTION=53
|
||||||
CONSTRUCTS=54
|
CONSTRUCTOR=54
|
||||||
INPUT=55
|
CONSTRUCTS=55
|
||||||
CONFORM=56
|
INPUT=56
|
||||||
AS=57
|
CONFORM=57
|
||||||
BIND=58
|
AS=58
|
||||||
STATIC=59
|
BIND=59
|
||||||
TO=60
|
STATIC=60
|
||||||
PRIVATE=61
|
TO=61
|
||||||
SHARED=62
|
PRIVATE=62
|
||||||
STATE=63
|
SHARED=63
|
||||||
EDGE=64
|
STATE=64
|
||||||
PROJECTION=65
|
EDGE=65
|
||||||
WITH=66
|
PROJECTION=66
|
||||||
USING=67
|
WITH=67
|
||||||
ACCEPT=68
|
USING=68
|
||||||
VIA=69
|
ACCEPT=69
|
||||||
MATERIALIZE=70
|
VIA=70
|
||||||
IF=71
|
MATERIALIZE=71
|
||||||
ABSENT=72
|
IF=72
|
||||||
ON=73
|
ABSENT=73
|
||||||
POLICY=74
|
ON=74
|
||||||
DEFAULT=75
|
POLICY=75
|
||||||
SOURCE=76
|
DEFAULT=76
|
||||||
REPOSITORY=77
|
SOURCE=77
|
||||||
COMMIT=78
|
REPOSITORY=78
|
||||||
REVISION=79
|
COMMIT=79
|
||||||
SEMANTIC_MAJOR=80
|
REVISION=80
|
||||||
ON_DELETE=81
|
SEMANTIC_MAJOR=81
|
||||||
LIFECYCLE=82
|
ON_DELETE=82
|
||||||
RETAIN_OTHER=83
|
LIFECYCLE=83
|
||||||
KEYED=84
|
RETAIN_OTHER=84
|
||||||
PUBLIC_TRAVERSAL=85
|
KEYED=85
|
||||||
ID=86
|
PUBLIC_TRAVERSAL=86
|
||||||
DOC=87
|
ID=87
|
||||||
MODE=88
|
DOC=88
|
||||||
EMITS=89
|
MODE=89
|
||||||
RECEIVER=90
|
EMITS=90
|
||||||
REQUIRES=91
|
RECEIVER=91
|
||||||
ANY=92
|
REQUIRES=92
|
||||||
GET=93
|
ANY=93
|
||||||
SET=94
|
GET=94
|
||||||
WATCH=95
|
SET=95
|
||||||
START=96
|
WATCH=96
|
||||||
STOP=97
|
START=97
|
||||||
READ=98
|
STOP=98
|
||||||
WRITE=99
|
READ=99
|
||||||
RESOLVE=100
|
WRITE=100
|
||||||
CONNECT=101
|
RESOLVE=101
|
||||||
DISCONNECT=102
|
CONNECT=102
|
||||||
CALL=103
|
DISCONNECT=103
|
||||||
WATCH_START=104
|
CALL=104
|
||||||
WATCH_STOP=105
|
WATCH_START=105
|
||||||
SUBSCRIBE=106
|
WATCH_STOP=106
|
||||||
UNSUBSCRIBE=107
|
SUBSCRIBE=107
|
||||||
REGISTER=108
|
UNSUBSCRIBE=108
|
||||||
CRDT=109
|
REGISTER=109
|
||||||
OPTIONAL_ONE=110
|
CRDT=110
|
||||||
EXACTLY_ONE=111
|
OPTIONAL_ONE=111
|
||||||
MANY_UNIQUE=112
|
EXACTLY_ONE=112
|
||||||
MANY=113
|
MANY_UNIQUE=113
|
||||||
ORDERED=114
|
MANY=114
|
||||||
UNIT=115
|
ORDERED=115
|
||||||
WATCH_HANDLE=116
|
UNIT=116
|
||||||
MESSAGE=117
|
WATCH_HANDLE=117
|
||||||
ATOM_REF=118
|
MESSAGE=118
|
||||||
INTERFACE_REF=119
|
ATOM_REF=119
|
||||||
OPTIONAL=120
|
INTERFACE_REF=120
|
||||||
LIST=121
|
OPTIONAL=121
|
||||||
RECORD=122
|
LIST=122
|
||||||
BOOL=123
|
RECORD=123
|
||||||
BYTES=124
|
BOOL=124
|
||||||
DOUBLE=125
|
BYTES=125
|
||||||
INT32=126
|
DOUBLE=126
|
||||||
INT64=127
|
INT32=127
|
||||||
STRING=128
|
INT64=128
|
||||||
UINT32=129
|
STRING=129
|
||||||
UINT64=130
|
UINT32=130
|
||||||
TRUE=131
|
UINT64=131
|
||||||
FALSE=132
|
TRUE=132
|
||||||
NULL=133
|
FALSE=133
|
||||||
ARROW=134
|
NULL=134
|
||||||
COLON=135
|
ARROW=135
|
||||||
SEMI=136
|
COLON=136
|
||||||
COMMA=137
|
SEMI=137
|
||||||
DOT=138
|
COMMA=138
|
||||||
LBRACE=139
|
DOT=139
|
||||||
RBRACE=140
|
LBRACE=140
|
||||||
LBRACK=141
|
RBRACE=141
|
||||||
RBRACK=142
|
LBRACK=142
|
||||||
LPAREN=143
|
RBRACK=143
|
||||||
RPAREN=144
|
LPAREN=144
|
||||||
LT=145
|
RPAREN=145
|
||||||
GT=146
|
LT=146
|
||||||
AMP=147
|
GT=147
|
||||||
EQUAL=148
|
AMP=148
|
||||||
INTEGER=149
|
EQUAL=149
|
||||||
JSON_NUMBER=150
|
INTEGER=150
|
||||||
IDENTIFIER=151
|
JSON_NUMBER=151
|
||||||
STRING_LITERAL=152
|
IDENTIFIER=152
|
||||||
LINE_COMMENT=153
|
STRING_LITERAL=153
|
||||||
BLOCK_COMMENT=154
|
LINE_COMMENT=154
|
||||||
WS=155
|
BLOCK_COMMENT=155
|
||||||
|
WS=156
|
||||||
'edit'=1
|
'edit'=1
|
||||||
'module'=2
|
'module'=2
|
||||||
'contract'=3
|
'contract'=3
|
||||||
@@ -202,102 +203,103 @@ WS=155
|
|||||||
'interfaces'=47
|
'interfaces'=47
|
||||||
'package'=48
|
'package'=48
|
||||||
'value'=49
|
'value'=49
|
||||||
'relation'=50
|
'field'=50
|
||||||
'operation'=51
|
'relation'=51
|
||||||
'function'=52
|
'operation'=52
|
||||||
'constructor'=53
|
'function'=53
|
||||||
'constructs'=54
|
'constructor'=54
|
||||||
'input'=55
|
'constructs'=55
|
||||||
'conform'=56
|
'input'=56
|
||||||
'as'=57
|
'conform'=57
|
||||||
'bind'=58
|
'as'=58
|
||||||
'static'=59
|
'bind'=59
|
||||||
'to'=60
|
'static'=60
|
||||||
'private'=61
|
'to'=61
|
||||||
'shared'=62
|
'private'=62
|
||||||
'state'=63
|
'shared'=63
|
||||||
'edge'=64
|
'state'=64
|
||||||
'projection'=65
|
'edge'=65
|
||||||
'with'=66
|
'projection'=66
|
||||||
'using'=67
|
'with'=67
|
||||||
'accept'=68
|
'using'=68
|
||||||
'via'=69
|
'accept'=69
|
||||||
'materialize'=70
|
'via'=70
|
||||||
'if'=71
|
'materialize'=71
|
||||||
'absent'=72
|
'if'=72
|
||||||
'on'=73
|
'absent'=73
|
||||||
'policy'=74
|
'on'=74
|
||||||
'default'=75
|
'policy'=75
|
||||||
'source'=76
|
'default'=76
|
||||||
'repository'=77
|
'source'=77
|
||||||
'commit'=78
|
'repository'=78
|
||||||
'revision'=79
|
'commit'=79
|
||||||
'semantic-major'=80
|
'revision'=80
|
||||||
'on-delete'=81
|
'semantic-major'=81
|
||||||
'lifecycle'=82
|
'on-delete'=82
|
||||||
'retain-other'=83
|
'lifecycle'=83
|
||||||
'keyed'=84
|
'retain-other'=84
|
||||||
'public-traversal'=85
|
'keyed'=85
|
||||||
'id'=86
|
'public-traversal'=86
|
||||||
'doc'=87
|
'id'=87
|
||||||
'mode'=88
|
'doc'=88
|
||||||
'emits'=89
|
'mode'=89
|
||||||
'receiver'=90
|
'emits'=90
|
||||||
'requires'=91
|
'receiver'=91
|
||||||
'any'=92
|
'requires'=92
|
||||||
'get'=93
|
'any'=93
|
||||||
'set'=94
|
'get'=94
|
||||||
'watch'=95
|
'set'=95
|
||||||
'start'=96
|
'watch'=96
|
||||||
'stop'=97
|
'start'=97
|
||||||
'read'=98
|
'stop'=98
|
||||||
'write'=99
|
'read'=99
|
||||||
'resolve'=100
|
'write'=100
|
||||||
'connect'=101
|
'resolve'=101
|
||||||
'disconnect'=102
|
'connect'=102
|
||||||
'call'=103
|
'disconnect'=103
|
||||||
'watch-start'=104
|
'call'=104
|
||||||
'watch-stop'=105
|
'watch-start'=105
|
||||||
'subscribe'=106
|
'watch-stop'=106
|
||||||
'unsubscribe'=107
|
'subscribe'=107
|
||||||
'register'=108
|
'unsubscribe'=108
|
||||||
'crdt'=109
|
'register'=109
|
||||||
'optional-one'=110
|
'crdt'=110
|
||||||
'exactly-one'=111
|
'optional-one'=111
|
||||||
'many-unique'=112
|
'exactly-one'=112
|
||||||
'many'=113
|
'many-unique'=113
|
||||||
'ordered'=114
|
'many'=114
|
||||||
'unit'=115
|
'ordered'=115
|
||||||
'watch-handle'=116
|
'unit'=116
|
||||||
'message'=117
|
'watch-handle'=117
|
||||||
'atom-ref'=118
|
'message'=118
|
||||||
'interface-ref'=119
|
'atom-ref'=119
|
||||||
'optional'=120
|
'interface-ref'=120
|
||||||
'list'=121
|
'optional'=121
|
||||||
'record'=122
|
'list'=122
|
||||||
'bool'=123
|
'record'=123
|
||||||
'bytes'=124
|
'bool'=124
|
||||||
'double'=125
|
'bytes'=125
|
||||||
'int32'=126
|
'double'=126
|
||||||
'int64'=127
|
'int32'=127
|
||||||
'string'=128
|
'int64'=128
|
||||||
'uint32'=129
|
'string'=129
|
||||||
'uint64'=130
|
'uint32'=130
|
||||||
'true'=131
|
'uint64'=131
|
||||||
'false'=132
|
'true'=132
|
||||||
'null'=133
|
'false'=133
|
||||||
'->'=134
|
'null'=134
|
||||||
':'=135
|
'->'=135
|
||||||
';'=136
|
':'=136
|
||||||
','=137
|
';'=137
|
||||||
'.'=138
|
','=138
|
||||||
'{'=139
|
'.'=139
|
||||||
'}'=140
|
'{'=140
|
||||||
'['=141
|
'}'=141
|
||||||
']'=142
|
'['=142
|
||||||
'('=143
|
']'=143
|
||||||
')'=144
|
'('=144
|
||||||
'<'=145
|
')'=145
|
||||||
'>'=146
|
'<'=146
|
||||||
'&'=147
|
'>'=147
|
||||||
'='=148
|
'&'=148
|
||||||
|
'='=149
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -529,6 +529,7 @@ const lowerValueMember = (state: LoweringState, context: ValueMemberContext): In
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
kind: "value",
|
kind: "value",
|
||||||
|
...(context.FIELD() ? { nativeField: true as const } : {}),
|
||||||
...(context.queryReadContract()
|
...(context.queryReadContract()
|
||||||
? {
|
? {
|
||||||
queryRead: {
|
queryRead: {
|
||||||
@@ -794,6 +795,7 @@ const lowerInterfaceTemplate = (
|
|||||||
const type = types.expression(value.valueType());
|
const type = types.expression(value.valueType());
|
||||||
return {
|
return {
|
||||||
kind: "value",
|
kind: "value",
|
||||||
|
...(value.FIELD() ? { nativeField: true as const } : {}),
|
||||||
...(value.queryReadContract()
|
...(value.queryReadContract()
|
||||||
? {
|
? {
|
||||||
queryRead: {
|
queryRead: {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ export const instantiateInterface = (
|
|||||||
return {
|
return {
|
||||||
...common,
|
...common,
|
||||||
kind: "value",
|
kind: "value",
|
||||||
|
...(member.nativeField ? { nativeField: true as const } : {}),
|
||||||
...(member.queryRead ? { queryRead: { ...member.queryRead } } : {}),
|
...(member.queryRead ? { queryRead: { ...member.queryRead } } : {}),
|
||||||
valueType: substitution.value(member.valueType, member.displayName),
|
valueType: substitution.value(member.valueType, member.displayName),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ interface InterfaceMemberBase<Type = ValueType> {
|
|||||||
|
|
||||||
export interface ValueInterfaceMember<Type = ValueType> extends InterfaceMemberBase<Type> {
|
export interface ValueInterfaceMember<Type = ValueType> extends InterfaceMemberBase<Type> {
|
||||||
kind: "value";
|
kind: "value";
|
||||||
|
/** Every operation resolves directly to the same native state slot. */
|
||||||
|
nativeField?: true;
|
||||||
queryRead?: QueryReadContract;
|
queryRead?: QueryReadContract;
|
||||||
valueType: Type;
|
valueType: Type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,6 +615,23 @@ const collectIdentityIndexes = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (member.kind === "value" && member.nativeField) {
|
||||||
|
const names = member.operations.map((o) => o.displayName);
|
||||||
|
if (
|
||||||
|
!isStorableType(member.valueType) ||
|
||||||
|
!names.includes("get") ||
|
||||||
|
names.some((n) => !["get", "set", "edit"].includes(n)) ||
|
||||||
|
(names.includes("set") && names.includes("edit"))
|
||||||
|
)
|
||||||
|
issue(
|
||||||
|
issues,
|
||||||
|
"invalid-state-binding",
|
||||||
|
memberPath,
|
||||||
|
"Fields require a storable value, a native getter and at most one setter or editor",
|
||||||
|
);
|
||||||
|
if (member.queryRead && member.queryRead.execution !== "native")
|
||||||
|
issue(issues, "invalid-query-contract", memberPath, "Fields cannot have package-backed query reads");
|
||||||
|
}
|
||||||
requireText(issues, member.id, `${memberPath}.id`, "Member ID");
|
requireText(issues, member.id, `${memberPath}.id`, "Member ID");
|
||||||
requireText(issues, member.displayName, `${memberPath}.displayName`, "Member name");
|
requireText(issues, member.displayName, `${memberPath}.displayName`, "Member name");
|
||||||
if (memberIds.has(member.id)) {
|
if (memberIds.has(member.id)) {
|
||||||
@@ -1758,6 +1775,34 @@ const validateConformances = (
|
|||||||
}
|
}
|
||||||
} else binding = entry.binding;
|
} else binding = entry.binding;
|
||||||
const member = operationEntry.member;
|
const member = operationEntry.member;
|
||||||
|
if (member.kind === "value" && member.nativeField) {
|
||||||
|
const primitive = { get: "read", set: "write", edit: "edit" }[operation.displayName];
|
||||||
|
const getter = member.operations.find((o) => o.displayName === "get");
|
||||||
|
let read: Binding | undefined;
|
||||||
|
try {
|
||||||
|
if (getter)
|
||||||
|
read = resolveForwardedBinding(
|
||||||
|
workspace,
|
||||||
|
conformance.atomId,
|
||||||
|
conformance.interfaceRevisionId,
|
||||||
|
getter.id,
|
||||||
|
).binding;
|
||||||
|
} catch {}
|
||||||
|
if (
|
||||||
|
binding.kind !== "state" ||
|
||||||
|
binding.primitive !== primitive ||
|
||||||
|
read?.kind !== "state" ||
|
||||||
|
read.primitive !== "read" ||
|
||||||
|
read.slotId !== binding.slotId
|
||||||
|
)
|
||||||
|
issue(
|
||||||
|
issues,
|
||||||
|
"invalid-state-binding",
|
||||||
|
bindingPath,
|
||||||
|
"Field operations must resolve to the same native state slot",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
member.kind === "value" &&
|
member.kind === "value" &&
|
||||||
operation.displayName === "edit" &&
|
operation.displayName === "edit" &&
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export interface PublicOperationContract {
|
|||||||
execution: ExecutionContract;
|
execution: ExecutionContract;
|
||||||
input: unknown;
|
input: unknown;
|
||||||
output: unknown;
|
output: unknown;
|
||||||
|
fieldPolicy?: "register" | "crdt";
|
||||||
}
|
}
|
||||||
export function publicOperationContract(
|
export function publicOperationContract(
|
||||||
iface: InterfaceRevision,
|
iface: InterfaceRevision,
|
||||||
@@ -29,7 +30,20 @@ export function publicOperationContract(
|
|||||||
"Expected a closed interface call operation",
|
"Expected a closed interface call operation",
|
||||||
);
|
);
|
||||||
const execution = operation.execution ?? { kind: "remote" };
|
const execution = operation.execution ?? { kind: "remote" };
|
||||||
|
const member = iface.members.find((m) => m.operations.includes(operation))!;
|
||||||
|
const fieldPolicy =
|
||||||
|
member.kind === "value" &&
|
||||||
|
operation.scope !== "class" &&
|
||||||
|
execution.kind === "transaction" &&
|
||||||
|
execution.targets.includes("browser")
|
||||||
|
? operation.displayName === "edit"
|
||||||
|
? "crdt"
|
||||||
|
: member.nativeField && operation.displayName === "set"
|
||||||
|
? "register"
|
||||||
|
: undefined
|
||||||
|
: undefined;
|
||||||
return {
|
return {
|
||||||
|
...(fieldPolicy ? { fieldPolicy } : {}),
|
||||||
interface: iface.revisionId,
|
interface: iface.revisionId,
|
||||||
operation: operation.id,
|
operation: operation.id,
|
||||||
scope: operation.scope ?? "object",
|
scope: operation.scope ?? "object",
|
||||||
@@ -116,15 +130,17 @@ export function generateInterfaceClientBindings(
|
|||||||
}
|
}
|
||||||
const operations = member.operations
|
const operations = member.operations
|
||||||
.filter((op) => op.mode === "call")
|
.filter((op) => op.mode === "call")
|
||||||
.map(
|
.map((op) => {
|
||||||
(op) =>
|
const contract = publicOperationContract(iface, op);
|
||||||
`${JSON.stringify(op.displayName)}: defineInterfaceOperation<${tsType(op.inputType)}, ${tsType(op.outputType)}, ${JSON.stringify(publicOperationContract(iface, op).execution)}>(${JSON.stringify(publicOperationContract(iface, op))})`,
|
return contract.fieldPolicy && member.kind === "value"
|
||||||
);
|
? `${JSON.stringify(op.displayName)}: defineFieldOperation<${tsType(member.valueType)}, ${JSON.stringify(contract.fieldPolicy)}, ${JSON.stringify(contract.execution)}>(${JSON.stringify(contract)})`
|
||||||
|
: `${JSON.stringify(op.displayName)}: defineInterfaceOperation<${tsType(op.inputType)}, ${tsType(op.outputType)}, ${JSON.stringify(contract.execution)}>(${JSON.stringify(contract)})`;
|
||||||
|
});
|
||||||
return `${JSON.stringify(member.displayName)}: {${operations.join(",\n")}}`;
|
return `${JSON.stringify(member.displayName)}: {${operations.join(",\n")}}`;
|
||||||
});
|
});
|
||||||
return `${JSON.stringify(alias)}: {${members.join(",\n")}}`;
|
return `${JSON.stringify(alias)}: {${members.join(",\n")}}`;
|
||||||
});
|
});
|
||||||
return `// Generated from imported interface contracts. Regenerate; do not edit.\nimport { defineModuleMember, defineInterfaceOperation, type PreparedChange, type ManagedReference } from ${JSON.stringify(runtimeModule)};\nexport const interfaces = {${entries.join(",\n")}} as const;\n`;
|
return `// Generated from imported interface contracts. Regenerate; do not edit.\nimport { defineModuleMember, defineInterfaceOperation, defineFieldOperation, type PreparedChange, type ManagedReference } from ${JSON.stringify(runtimeModule)};\nexport const interfaces = {${entries.join(",\n")}} as const;\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generatePackageQueryClientBindings(
|
export function generatePackageQueryClientBindings(
|
||||||
|
|||||||
@@ -22,6 +22,95 @@ const parsed = compileCapabilityResourceSource(
|
|||||||
assert.ok(parsed.ok && parsed.resource.kind === "interface", JSON.stringify(parsed.diagnostics));
|
assert.ok(parsed.ok && parsed.resource.kind === "interface", JSON.stringify(parsed.diagnostics));
|
||||||
const iface = parsed.resource.revision;
|
const iface = parsed.resource.revision;
|
||||||
const environment = { interfaces: new Map([["Data", iface]]), interfaceClosure: [iface] };
|
const environment = { interfaces: new Map([["Data", iface]]), interfaceClosure: [iface] };
|
||||||
|
test("native fields certify one storage slot; only browser writes get live descriptors", () => {
|
||||||
|
const parsed = compileCapabilityResourceSource(
|
||||||
|
`interface Fields id "fields" revision "fields@1" {
|
||||||
|
queryable field position id "position" : string {
|
||||||
|
get id "position:get" execution snapshot targets [browser, server];
|
||||||
|
set id "position:set" execution transaction targets [browser, server];
|
||||||
|
}
|
||||||
|
field remote id "remote" : string {
|
||||||
|
get id "remote:get";
|
||||||
|
set id "remote:set";
|
||||||
|
}
|
||||||
|
value arbitrary id "arbitrary" : string {
|
||||||
|
get id "arbitrary:get" execution snapshot targets [browser,server];
|
||||||
|
set id "arbitrary:set" execution transaction targets [browser, server];
|
||||||
|
}
|
||||||
|
value text id "text" : string {
|
||||||
|
get id "text:get";
|
||||||
|
edit id "text:edit" execution transaction targets [browser, server];
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
{ source },
|
||||||
|
);
|
||||||
|
assert.ok(parsed.ok && parsed.resource.kind === "interface", JSON.stringify(parsed.diagnostics));
|
||||||
|
const revision = parsed.resource.revision;
|
||||||
|
const generated = generateInterfaceClientBindings({ Fields: revision });
|
||||||
|
assert.match(generated, /defineFieldOperation<string, "register",/);
|
||||||
|
assert.match(generated, /defineFieldOperation<string, "crdt",/);
|
||||||
|
for (const member of revision.members) {
|
||||||
|
const operation = member.operations.at(-1)!;
|
||||||
|
assert.equal(
|
||||||
|
publicOperationContract(revision, operation).fieldPolicy,
|
||||||
|
member.displayName === "position" ? "register" : member.displayName === "text" ? "crdt" : undefined,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const workspace = `workspace W id "w" revision "w@1" commit "${source.commit}" {
|
||||||
|
import interface Fields; atom A id "a";
|
||||||
|
conform A as Fields id "a:fields" {
|
||||||
|
private state First id "first" on A : string policy register default "";
|
||||||
|
private state Second id "second" on A : string policy register default "";
|
||||||
|
private state Text id "text" on A : string policy crdt(string);
|
||||||
|
initialize { text to state Text; };
|
||||||
|
bind position.get to state First.read;
|
||||||
|
bind position.set to state First.write;
|
||||||
|
bind remote.get to state Second.read;
|
||||||
|
bind remote.set to state Second.write;
|
||||||
|
bind arbitrary.get to state Second.read;
|
||||||
|
bind arbitrary.set to state Second.write;
|
||||||
|
bind text.get to state Text.read;
|
||||||
|
bind text.edit to state Text.edit;
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
const env = { interfaces: new Map([["Fields", revision]]) };
|
||||||
|
const good = compileCapabilitySource(workspace, "workspace.qx", env);
|
||||||
|
assert.ok(good.ok, JSON.stringify(good.diagnostics));
|
||||||
|
const bad = compileCapabilitySource(
|
||||||
|
workspace.replace("bind position.set to state First.write", "bind position.set to state Second.write"),
|
||||||
|
"workspace.qx",
|
||||||
|
env,
|
||||||
|
);
|
||||||
|
assert.equal(bad.ok, false);
|
||||||
|
assert.ok(
|
||||||
|
bad.diagnostics.some((d) => d.message.includes("same native state slot")),
|
||||||
|
JSON.stringify(bad.diagnostics),
|
||||||
|
);
|
||||||
|
const forwarded = workspace
|
||||||
|
.replace("bind position.get to state First.read", "bind position.get to interface Fields.arbitrary.get")
|
||||||
|
.replace("bind position.set to state First.write", "bind position.set to interface Fields.arbitrary.set");
|
||||||
|
const goodForward = compileCapabilitySource(forwarded, "workspace.qx", env);
|
||||||
|
assert.ok(goodForward.ok, JSON.stringify(goodForward.diagnostics));
|
||||||
|
const pkg = compileCapabilityResourceSource(
|
||||||
|
`package Setter id "setter" revision "setter@1" {
|
||||||
|
operation replaceValue id "write" : string -> unit mode call execution transaction targets [browser,server] receiver any;
|
||||||
|
}`,
|
||||||
|
{ source },
|
||||||
|
);
|
||||||
|
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
|
||||||
|
const badForward = compileCapabilitySource(
|
||||||
|
forwarded
|
||||||
|
.replace("import interface Fields;", "import interface Fields; import package Setter;")
|
||||||
|
.replace("bind arbitrary.set to state Second.write", "bind arbitrary.set to package Setter.replaceValue"),
|
||||||
|
"workspace.qx",
|
||||||
|
{ ...env, packages: new Map([["Setter", pkg.resource.revision]]) },
|
||||||
|
);
|
||||||
|
assert.equal(badForward.ok, false);
|
||||||
|
assert.ok(
|
||||||
|
badForward.diagnostics.some((d) => d.message.includes("same native state slot")),
|
||||||
|
JSON.stringify(badForward.diagnostics),
|
||||||
|
);
|
||||||
|
});
|
||||||
const compile = async () => {
|
const compile = async () => {
|
||||||
const pkg = compileCapabilityResourceSource(
|
const pkg = compileCapabilityResourceSource(
|
||||||
`import interface Data; package Views id "views" revision "views@1" {
|
`import interface Data; package Views id "views" revision "views@1" {
|
||||||
|
|||||||
Reference in New Issue
Block a user