Skip to content

Commit

Permalink
Merge pull request #128 from fink-lang/semantics
Browse files Browse the repository at this point in the history
Semantics
  • Loading branch information
kollhof authored Aug 2, 2021
2 parents 560ccd9 + 6ab832b commit 6c0c6bd
Show file tree
Hide file tree
Showing 28 changed files with 703 additions and 787 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: setup nodejs
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 16.5

- name: install dependencies
env:
Expand Down
1,068 changes: 572 additions & 496 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"devDependencies": {
"@fink/cli": "^8.0.0",
"@fink/jest": "^7.2.0",
"@fink/larix": "^19.0.0",
"@fink/larix": "^20.0.0",
"@fink/loxia": "^22.0.0",
"commitizen": "^4.1.2",
"cz-conventional-changelog": "^3.1.0",
Expand Down
5 changes: 3 additions & 2 deletions src/generate.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ babel_traverse = import '@babel/traverse'
{default: traverse} = babel_traverse

{transformFromAstSync} = import '@babel/core'
{try_catch} = import '@fink/js-interop/errors.fnk'

{transform} = import './lang/transform.fnk'
{init_ctx} = import './lang/init.fnk'
Expand All @@ -16,7 +17,7 @@ babel_traverse = import '@babel/traverse'
transform_file = fn fink_ast, code, filename, options:
ctx = init_ctx code, filename, options

[error, [js_ast]=[]] = try:
[error, [js_ast]=[]] = try_catch fn:
transform fink_ast, ctx

extras = match options:
Expand Down Expand Up @@ -46,7 +47,7 @@ babel_generate = fn ast, filename, source, options:
sourceMaps: source_maps
...babel

[error, result] = try:
[error, result] = try_catch fn:
{code, map: source_map} = transformFromAstSync ast, source, babel_opts
{code, source_map, errors: []}

Expand Down
61 changes: 25 additions & 36 deletions src/js/do-expression.fnk
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
babel_types = import '@babel/types'
{
assignmentExpression, returnStatement, expressionStatement
assignmentExpression, returnStatement
isDoExpression, isBlockStatement, isLabeledStatement
isVariableDeclarator, isArrowFunctionExpression, isExpressionStatement
isAssignmentExpression
isReturnStatement
arrowFunctionExpression, callExpression
} = babel_types
Expand Down Expand Up @@ -61,6 +62,7 @@ last_expressions = fn path:
else:
[...last_expressions last]

--- istanbul ignore else ---
isLabeledStatement ?:
body = get_body path

Expand All @@ -72,47 +74,24 @@ last_expressions = fn path:

BreakStatement: fn brk:
last = brk.getSibling brk.key - 1
# TODO: don't add throw expr
match last.node:
{expression: {operator: 'throw'}}:
last.replaceWith
expressionStatement last.node.expression
brk.remove _
else:
# TODO: don't use mutation
items.push last
items.push last
undefined
items

else:
# isTryStatement
block = path.get'block'
handler = path.get 'handler'
body = get_body handler
list:
...last_expressions block
...last_expressions body



replace_with_return = fn path:
pipe last_expressions path:
map fn expr:
match expr:
{node: {expression: {operator: 'throw'}}}:
expr.replaceWith
wrap_with_comment_loc
expressionStatement expr.node.expression
expr.node.expression
else:
expr.replaceWith
wrap_with_comment_loc
returnStatement expr.node.expression
expr.node.expression
expr.replaceWith
wrap_with_comment_loc
returnStatement expr.node.expression
expr.node.expression

# TODO: no need for e.g. breaks after a return
sibl = expr.getSibling expr.key + 1
match sibl:
# TODO `?:`
--- istanbul ignore next ---
{}:
sibl.remove _
Expand Down Expand Up @@ -169,13 +148,23 @@ transform_do_expr = fn path:

replace_with_return path


isAssignmentExpression ?:
id = parent.get 'left'

pipe last_expressions path:
map fn expr:
expr.replaceWith
wrap_with_comment_loc
assignmentExpression '=', id.node, expr.node.expression
expr.node.expression

consume_all

parent.replaceWithMultiple path.node.body.body

else:
# TODO
# foo = match:
# spam:
# shrub
# ni
# foo
# TODO: {spam.ham.ni: {foo, bar} = spam
arrow = arrowFunctionExpression [], path.node
path.replaceWith
callExpression arrow, []
Expand Down
11 changes: 6 additions & 5 deletions src/js/types.fnk
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
babe_types = import '@babel/types'
{
variableDeclaration, variableDeclarator
nullLiteral, booleanLiteral, identifier, expressionStatement
nullLiteral, identifier, expressionStatement
binaryExpression, unaryExpression, assignmentExpression
} = babe_types

Expand All @@ -11,7 +11,7 @@ babe_types = import '@babel/types'



wrap = fn larix_node, js_node:
add_loc = fn larix_node, js_node:
{...js_node, loc: larix_node.loc}


Expand All @@ -23,14 +23,15 @@ eq = fn left, right: binaryExpression '===', left, right

undef = fn: identifier 'undefined'

false_ = fn: booleanLiteral false



not_nullish = fn value:
binaryExpression '!=', value, nullLiteral _


not_undefiend = fn value:
binaryExpression '!==', value, undef _



ident = fn name, ctx:
identifier escape_ident name, ctx
Expand Down
1 change: 0 additions & 1 deletion src/lang/async/init.test.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ describe 'await', fn:
task2 = fn foo: await (foo + 4)

task3 = fn foo:
bar = await foo ()
spam = await foo _
bar + 123

Expand Down
1 change: 0 additions & 1 deletion src/lang/async/init.test.fnk.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ exports[`await compiles 1`] = `
"export const task1 = async foo => -(await foo);
export const task2 = async foo => await (foo + 4);
export const task3 = async foo => {
const bar = await foo();
const spam = await foo();
return bar + 123;
};
Expand Down
5 changes: 1 addition & 4 deletions src/lang/call/call.fnk
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
babel_types = import '@babel/types'
{callExpression, identifier} = babel_types

{map, filter, zip, is_empty, length} = import '@fink/std-lib/iter.fnk'
{map, filter, zip, length} = import '@fink/std-lib/iter.fnk'

{transform, map_with_ctx, collect_with_ctx} = import '../transform.fnk'
{transform_with_partial, partial_wrapper, no_wrapper} = import '../partial/init.fnk'
Expand All @@ -24,9 +24,6 @@ transform_single_arg = fn [expr], ctx:
match expr:
{type: 'empty'}:
[[], ctx]
# TODO: remove in favour of using _ as empty?
{type: 'group', exprs: is_empty ?}:
[[], ctx]
else:
transform_multiple_args [expr], ctx

Expand Down
7 changes: 3 additions & 4 deletions src/lang/call/call.test.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ describe 'call', fn:
fink2js '
call1 = a ni, x=123, ...x
call2 = a ni
call3 = a ()
call4 = a _
call5 = a fn x: x * 2
call6 = a foo, , bar
call3 = a _
call4 = a fn x: x * 2
call5 = a foo, , bar
'
to_match_snapshot

Expand Down
5 changes: 2 additions & 3 deletions src/lang/call/call.test.fnk.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ exports[`call compiles 1`] = `
"export const call1 = a(ni, x = 123, ...x);
export const call2 = a(ni);
export const call3 = a();
export const call4 = a();
export const call5 = a(x => x * 2);
export const call6 = a(foo, undefined, bar);"
export const call4 = a(x => x * 2);
export const call5 = a(foo, undefined, bar);"
`;

exports[`call compiles as partial 1`] = `
Expand Down
2 changes: 1 addition & 1 deletion src/lang/call/pipe.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ transform_pipe = fn node, ctx:
start_value
...pipe_calls

[js, next_ctx]
[js, next_ctx]
19 changes: 12 additions & 7 deletions src/lang/conditionals/match.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ babel_types = import '@babel/types'
} = babel_types
{map, filter, length, is_empty} = import '@fink/std-lib/iter.fnk'

{eq, not_nullish, typof, consts, unique_ident} = import '../../js/types.fnk'
{eq, not_nullish, not_undefiend, typof, consts, unique_ident} = import '../../js/types.fnk'

{get_key} = import '../literals/record.fnk'
{wrap_with_comment_loc} = import '../comments/init.fnk'
Expand All @@ -31,14 +31,19 @@ is_iterable = fn value:


comp = fn id, expected, ctx:
value_ctx = {...ctx, partial_ident: id}
[wrap_with_partial, value, {partial_ident: _, ...next_ctx}] = transform_with_partial expected, value_ctx, false
match expected:
{type: 'partial'}:
cond = not_undefiend id
[cond, ctx]
else:
value_ctx = {...ctx, partial_ident: id}
[wrap_with_partial, value, {partial_ident: _, ...next_ctx}] = transform_with_partial expected, value_ctx, false

cond = match wrap_with_partial:
false: eq id, value
else: value
cond = match wrap_with_partial:
false: eq id, value
else: value

[cond, next_ctx]
[cond, next_ctx]



Expand Down
21 changes: 14 additions & 7 deletions src/lang/conditionals/match.test.fnk
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ describe 'match', fn:
? > 123: ni

# simple call
? (): ni
? _: ni

# simple as call arg
shrub ?: ni

# any value
?: true
'
to_match_snapshot

Expand Down Expand Up @@ -69,6 +71,7 @@ describe 'match iterables', fn:
match shrub:
# deep iterable comparison
[1, 2, [ni]]: ni
# TODO: fix semantics for matching [], {}
[1, 2, [], {}]: foo
[1, [2, 3], 4]: bar
[1, [2, [3, 4]], [5, 6], 7]: spam
Expand Down Expand Up @@ -96,15 +99,16 @@ describe 'match iterables', fn:
# nested unary
[not ?]: ni

# any value
[?]: true

# nested binary
[? > 123]: ni

# nested call
[? ()]: ni
[? _]: ni

# nested member call
[?.is_foo ()]: ni
[?.is_foo _]: ni

# nested as call arg
Expand All @@ -122,7 +126,9 @@ describe 'match records', fn:
expect
fink2js "
match shrub:
# TODO: fix semantics for matching {}
{foo: {}}: spam + ni
# TODO: fix semantics for matching []
{foo: []}: spam + ni
{foo: 4, ni: {na, nu}}: spam + ni
{foo: 1, foo: {bar: 'spam'}, shrub: {na: 'nu'}}: ni
Expand Down Expand Up @@ -178,18 +184,19 @@ describe 'match records', fn:
{spam: ? > 123}: ni

# nested call
{spam: ? ()}: ni
{spam: ? _}: ni

# nested member call
{spam: ?.is_foo ()}: ni
{spam: ?.is_foo _}: ni

# nested as call arg
{spam: is_foo ?}: ni

{spam, ...is_empty ?}: ni
{spam, ...("foo" in ?)}: ni

# any value
{spam: ?}: true
'
to_match_snapshot

Expand All @@ -202,10 +209,10 @@ describe 'match value assertions', fn:
foo = match bar:
spam:
ni
throw foobar
shrub foobar
else:
shrub
throw ni
spam ni
'
to_match_snapshot

Loading

0 comments on commit 6c0c6bd

Please sign in to comment.