Skip to content

Commit

Permalink
Named Arguments (#625)
Browse files Browse the repository at this point in the history
Co-authored-by: jansul <jon@sul.ly>
Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
  • Loading branch information
3 people authored Sep 17, 2023
1 parent d04f5c0 commit 5acd5b8
Show file tree
Hide file tree
Showing 24 changed files with 228 additions and 23 deletions.
4 changes: 2 additions & 2 deletions documentation/Language/Locale.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ or if it's a function if can be called:
locale en {
ui: {
buttons: {
ok: (param1 : String, param2 : String) {
"Button #{param1} #{param2}!"
ok: (param1 : String, param2 : String) {
"Button #{param1} #{param2}!"
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions spec/compilers/call_labelled
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
component Main {
fun test (argument1 : String, argument2: Number) : Html {
<div/>
}

fun render : Html {
test(argument2: 0, argument1: "")
}
}
--------------------------------------------------------------------------------
class A extends _C {
a(b, c) {
return _h("div", {});
}

render() {
return this.a(``, 0);
}
};

A.displayName = "Main";
39 changes: 39 additions & 0 deletions spec/type_checking/function_call_labelled
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
component Main {
fun test (argument1 : String, argument2: Number) : Html {
<div/>
}

fun render : Html {
test(argument2: 0, argument1: "")
}
}
---------------------------------------------------------CallWithMixedArguments
component Main {
fun test (argument1 : String, argument2: Number) : Html {
<div/>
}

fun render : Html {
test(0, argument1: "")
}
}
---------------------------------------------------------CallWithMixedArguments
component Main {
fun test (argument1 : String, argument2: Number) : Html {
<div/>
}

fun render : Html {
test(argument2: 0, "")
}
}
-----------------------------------------------------------CallNotFoundArgument
component Main {
fun test (argument1 : String, argument2: Number) : Html {
<div/>
}

fun render : Html {
test(argument3: 0, argument1: "")
}
}
2 changes: 1 addition & 1 deletion src/ast/call.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Mint
class Call < Node
getter arguments, expression

def initialize(@arguments : Array(Expression),
def initialize(@arguments : Array(CallExpression),
@expression : Expression,
@input : Data,
@from : Int32,
Expand Down
14 changes: 14 additions & 0 deletions src/ast/call_expression.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Mint
class Ast
class CallExpression < Node
getter name, expression

def initialize(@expression : Expression,
@name : Variable?,
@input : Data,
@from : Int32,
@to : Int32)
end
end
end
end
12 changes: 10 additions & 2 deletions src/ast/pipe.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,27 @@ module Mint
end

def call
arg =
Ast::CallExpression.new(
expression: argument,
input: argument.input,
from: argument.from,
to: argument.to,
name: nil)

@call ||=
case item = expression
when Ast::Call
Ast::Call.new(
arguments: [argument] + item.arguments,
arguments: [arg] + item.arguments,
expression: item.expression,
input: item.input,
from: item.from,
to: item.to)
else
Ast::Call.new(
expression: expression,
arguments: [argument],
arguments: [arg],
input: input,
from: from,
to: to)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Mint

delegate lookups, checked, cache, component_records, to: @artifacts
delegate ast, types, variables, resolve_order, to: @artifacts
delegate record_field_lookup, locales, to: @artifacts
delegate record_field_lookup, locales, argument_order, to: @artifacts

getter js, style_builder, static_components, static_components_pool
getter build, relative
Expand Down
2 changes: 1 addition & 1 deletion src/compilers/block.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Mint
last =
statements.pop

if statements.empty?
if statements.empty? && !node.async?
if for_function
js.return(last)
else
Expand Down
2 changes: 1 addition & 1 deletion src/compilers/call.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Mint
compile node.expression

arguments =
compile node.arguments, ", "
compile node.arguments.sort_by { |item| argument_order.index(item) || -1 }, ", "

case
when node.expression.is_a?(Ast::InlineFunction)
Expand Down
7 changes: 7 additions & 0 deletions src/compilers/call_expression.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Mint
class Compiler
def _compile(node : Ast::CallExpression)
compile node.expression
end
end
end
14 changes: 14 additions & 0 deletions src/formatters/call_expression.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Mint
class Formatter
def format(node : Ast::CallExpression)
expression =
format node.expression

if name = node.name
"#{name.value}: #{expression}"
else
expression
end
end
end
end
13 changes: 13 additions & 0 deletions src/messages/call_not_found_argument.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
message CallNotFoundArgument do
title "Type Error"

block do
text "I was looking for the argument:"
bold name
text "but it's not there."
end

type_with_text function_type, "The type of the function is:"

snippet node, "The call is here:"
end
9 changes: 9 additions & 0 deletions src/messages/call_with_mixed_arguments.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
message CallWithMixedArguments do
title "Type Error"

block do
text "A call cannot have named and unamed arguments at the same time."
end

snippet node, "It is here:"
end
2 changes: 1 addition & 1 deletion src/parsers/call.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Mint
arguments = list(
terminator: ')',
separator: ','
) { expression.as(Ast::Expression?) }
) { call_expression.as(Ast::CallExpression?) }
whitespace

char ')', CallExpectedClosingParentheses
Expand Down
27 changes: 27 additions & 0 deletions src/parsers/call_expression.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Mint
class Parser
def call_expression : Ast::CallExpression?
start do |start_position|
name =
start do
next unless key = variable
whitespace

next unless char! ':'
whitespace

key
end

return unless expression = self.expression

Ast::CallExpression.new(
expression: expression,
from: start_position,
to: position,
input: data,
name: name)
end
end
end
end
2 changes: 1 addition & 1 deletion src/type_checker.cr
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module Mint

delegate checked, record_field_lookup, component_records, to: artifacts
delegate types, variables, ast, lookups, cache, to: artifacts
delegate assets, resolve_order, locales, to: artifacts
delegate assets, resolve_order, locales, argument_order, to: artifacts

delegate component?, component, stateful?, current_top_level_entity?, to: scope
delegate format, to: formatter
Expand Down
2 changes: 2 additions & 0 deletions src/type_checker/artifacts.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Mint
class Artifacts
getter ast, lookups, cache, checked, record_field_lookup, assets
getter types, variables, component_records, resolve_order, locales
getter argument_order

def initialize(@ast : Ast,
@component_records = {} of Ast::Component => Record,
Expand All @@ -13,6 +14,7 @@ module Mint
@types = {} of Ast::Node => Checkable,
@cache = {} of Ast::Node => Checkable,
@locales = {} of String => Hash(String, Ast::Node),
@argument_order = [] of Ast::Node,
@resolve_order = [] of Ast::Node,
@checked = Set(Ast::Node).new)
end
Expand Down
10 changes: 5 additions & 5 deletions src/type_checker/comparer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module Mint
parameters =
node.parameters.map { |param| fill(param, mapping).as(Checkable) }

Type.new(node.name, parameters)
Type.new(node.name, parameters, node.label)
else
node
end
Expand Down Expand Up @@ -113,7 +113,7 @@ module Mint
end

def fresh(node : Variable)
Variable.new(node.name)
Variable.new(node.name, node.label)
end

def fresh(node : Type, mapping = {} of Int32 => Variable)
Expand All @@ -131,7 +131,7 @@ module Mint
end
end

Type.new(node.name, params)
Type.new(node.name, params, node.label)
end

def fresh(node : PartialRecord)
Expand All @@ -142,7 +142,7 @@ module Mint
memo[key] = fresh value
end

PartialRecord.new(node.name, fields)
PartialRecord.new(node.name, fields, label: node.label)
end

def fresh(node : Record)
Expand All @@ -153,7 +153,7 @@ module Mint
memo[key] = fresh value
end

Record.new(node.name, fields)
Record.new(node.name, fields, label: node.label)
end

def prune(node : Variable)
Expand Down
5 changes: 4 additions & 1 deletion src/type_checker/record.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ module Mint
class TypeChecker
class Record
property parameters = [] of Checkable
property label : String?

getter name, fields, mappings

def initialize(
@name : String,
@fields = {} of String => Checkable,
@mappings = {} of String => String?
@mappings = {} of String => String?,
@label = nil
)
end

Expand Down
14 changes: 12 additions & 2 deletions src/type_checker/type.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ module Mint
getter name : String

property optional_count : Int32 = 0
property label : String?

def initialize(@name, @parameters = [] of Checkable)
def initialize(@name, @parameters = [] of Checkable, @label = nil)
end

def to_mint
Expand All @@ -18,7 +19,16 @@ module Mint
name
else
params =
parameters.map(&.to_pretty.as(String))
parameters.map do |param|
pretty =
param.to_pretty.as(String)

if param.label
"#{param.label}: #{pretty}"
else
pretty
end
end

if params.size > 1 || params[0].includes?("\n")
"#{name}(\n#{params.join(",\n").indent})"
Expand Down
4 changes: 3 additions & 1 deletion src/type_checker/variable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ module Mint

property parameters = [] of Checkable
property instance : Checkable?
property label : String?

getter name : String
getter id : Int32

def initialize(@name)
def initialize(@name, @label = nil)
@id = (@@id += 1)
end

Expand Down
1 change: 1 addition & 0 deletions src/type_checkers/argument.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Mint
node.default.try { |default| resolve default }

resolve_type(resolve(node.type))
.tap(&.label = node.name.try(&.value))
end
end
end
Loading

0 comments on commit 5acd5b8

Please sign in to comment.