1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-28 00:59:31 +00:00

Add variable constraints, rename type annotation checks to constraints, rename custom type to annotation

This commit is contained in:
Étienne Fildadut 2022-09-08 20:43:36 +09:00
parent 92a496e584
commit 3e658e4780
16 changed files with 237 additions and 118 deletions

View file

@ -307,8 +307,8 @@ common = {
if p.alias then
sig = sig .. ":" .. p.alias
end
if p.type_annotation then
sig = sig .. "::" .. p.type_annotation
if p.type_constraint then
sig = sig .. "::" .. p.type_constraint
end
if p.default then
sig = sig .. "=" .. p.default

View file

@ -8,17 +8,17 @@ local function parse(state)
for i=#state.queued_lines, 1, -1 do
local l = state.queued_lines[i]
local line, namespace = l.line, l.namespace
-- default arguments and type annotation
-- default arguments and type constraints
if line.type == "function" then
for _, param in ipairs(line.params) do
-- get type annotation
if param.type_annotation then
local type_exp, rem = expression(param.type_annotation, state, namespace)
if not type_exp then return nil, ("in type annotation, %s; at %s"):format(rem, line.source) end
-- get type constraints
if param.type_constraint then
local type_exp, rem = expression(param.type_constraint, state, namespace)
if not type_exp then return nil, ("in type constraint, %s; at %s"):format(rem, line.source) end
if rem:match("[^%s]") then
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param.full_name, rem, line.source)
end
param.type_annotation = type_exp
state.variable_constraints[param.full_name] = { pending = type_exp }
end
-- get default value
if param.default then
@ -28,20 +28,20 @@ local function parse(state)
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param.full_name, rem, line.source)
end
param.default = default_exp
-- extract type annotation from default value
-- extract type constraint from default value
if default_exp.type == "function call" and default_exp.called_name == "_::_" then
param.type_annotation = default_exp.argument.expression.right
state.variable_constraints[param.full_name] = { pending = default_exp.argument.expression.right }
end
end
end
-- assignment argument
if line.assignment and line.assignment.type_annotation then
local type_exp, rem = expression(line.assignment.type_annotation, state, namespace)
if not type_exp then return nil, ("in type annotation, %s; at %s"):format(rem, line.source) end
if line.assignment and line.assignment.type_constraint then
local type_exp, rem = expression(line.assignment.type_constraint, state, namespace)
if not type_exp then return nil, ("in type constraint, %s; at %s"):format(rem, line.source) end
if rem:match("[^%s]") then
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(line.assignment.full_name, rem, line.source)
end
line.assignment.type_annotation = type_exp
state.variable_constraints[line.assignment.full_name] = { pending = type_exp }
end
-- get list of scoped variables
-- (note includes every variables in the namespace of subnamespace, so subfunctions are scoped alongside this function)
@ -63,6 +63,15 @@ local function parse(state)
-- variable pending definition: expression will be evaluated when variable is needed
if line.type == "definition" then
state.variables[line.fqm].value.expression = line.expression
-- parse constraints
if line.constraint then
local type_exp, rem2 = expression(line.constraint, state, namespace)
if not type_exp then return nil, ("in type constraint, %s; at %s"):format(rem2, line.source) end
if rem2:match("[^%s]") then
return nil, ("unexpected characters after variable %q: %q; at %s"):format(line.fqm, rem2, line.source)
end
state.variable_constraints[line.fqm] = { pending = type_exp }
end
end
end
-- text (text & choice lines)

View file

@ -134,17 +134,17 @@ local function parse_line(line, state, namespace, parent_function)
local ok_param_alias, param_alias
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, func_namespace, line, state)
if not ok_param_alias then return ok_param_alias, param_rem end
-- get potential type annotation and default value
local type_annotation, default
-- get potential type constraints and default value
local type_constraint, default
if param_rem:match("^::") then
type_annotation = param_rem:match("^::(.*)$")
type_constraint = param_rem:match("^::(.*)$")
elseif param_rem:match("^=") then
default = param_rem:match("^=(.*)$")
elseif param_rem:match("[^%s]") then
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
end
-- add parameter
table.insert(r.params, { name = param_identifier, alias = param_alias, full_name = param_fqm, type_annotation = type_annotation, default = default, vararg = nil })
table.insert(r.params, { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = default, vararg = nil })
end
end
-- get assignment param
@ -160,15 +160,15 @@ local function parse_line(line, state, namespace, parent_function)
local ok_param_alias, param_alias
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, func_namespace, line, state)
if not ok_param_alias then return ok_param_alias, param_rem end
-- get potential type annotation
local type_annotation
-- get potential type constraint
local type_constraint
if param_rem:match("^::") then
type_annotation = param_rem:match("^::(.*)$")
type_constraint = param_rem:match("^::(.*)$")
elseif param_rem:match("[^%s]") then
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
end
-- add parameter
r.assignment = { name = param_identifier, alias = param_alias, full_name = param_fqm, type_annotation = type_annotation, default = nil, vararg = nil }
r.assignment = { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = nil, vararg = nil }
elseif rem:match("[^%s]") then
return nil, ("expected end-of-line at end of function definition line, but got %q; at %s"):format(rem, line.source)
end
@ -300,6 +300,10 @@ local function parse_line(line, state, namespace, parent_function)
local ok_alias
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
if not ok_alias then return ok_alias, rem end
-- type constraint
if rem:match("^::(.-)=") then
r.constraint, rem = rem:match("^::%s*(.-)%s*(=.*)$")
end
-- get expression
local exp = rem:match("^=(.*)$")
if not exp then return nil, ("expected \"= expression\" after %q in definition line; at %s"):format(rem, line.source) end
@ -509,6 +513,7 @@ local function parse(state, s, name, source)
local state_proxy = {
inject = {},
aliases = setmetatable({}, { __index = state.aliases }),
variable_constraints = setmetatable({}, { __index = state.variable_constraints }),
variables = setmetatable({}, { __index = state.aliases }),
functions = setmetatable({}, {
__index = function(self, key)
@ -541,6 +546,9 @@ local function parse(state, s, name, source)
for k,v in pairs(state_proxy.aliases) do
state.aliases[k] = v
end
for k,v in pairs(state_proxy.variable_constraints) do
state.variable_constraints[k] = v
end
for k,v in pairs(state_proxy.variables) do
state.variables[k] = v
end