mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 06:01:37 +03:00
Move TypeSignature into field of Function (#11364)
Move type-signature lines into `Function` field. Also implements #11293. Stacked on #11346.
This commit is contained in:
parent
d278ad636c
commit
4e4a1e1df2
@ -167,6 +167,10 @@ class Abstractor {
|
|||||||
}
|
}
|
||||||
case RawAst.Tree.Type.Function: {
|
case RawAst.Tree.Type.Function: {
|
||||||
const name = this.abstractTree(tree.name)
|
const name = this.abstractTree(tree.name)
|
||||||
|
const signatureLine = tree.signatureLine && {
|
||||||
|
signature: this.abstractTypeSignature(tree.signatureLine.signature),
|
||||||
|
newlines: Array.from(tree.signatureLine.newlines, this.abstractToken.bind(this)),
|
||||||
|
}
|
||||||
const private_ = tree.private && this.abstractToken(tree.private)
|
const private_ = tree.private && this.abstractToken(tree.private)
|
||||||
const argumentDefinitions = Array.from(tree.args, arg => ({
|
const argumentDefinitions = Array.from(tree.args, arg => ({
|
||||||
open: arg.open && this.abstractToken(arg.open),
|
open: arg.open && this.abstractToken(arg.open),
|
||||||
@ -186,7 +190,15 @@ class Abstractor {
|
|||||||
}))
|
}))
|
||||||
const equals = this.abstractToken(tree.equals)
|
const equals = this.abstractToken(tree.equals)
|
||||||
const body = tree.body !== undefined ? this.abstractTree(tree.body) : undefined
|
const body = tree.body !== undefined ? this.abstractTree(tree.body) : undefined
|
||||||
node = Function.concrete(this.module, private_, name, argumentDefinitions, equals, body)
|
node = Function.concrete(
|
||||||
|
this.module,
|
||||||
|
signatureLine,
|
||||||
|
private_,
|
||||||
|
name,
|
||||||
|
argumentDefinitions,
|
||||||
|
equals,
|
||||||
|
body,
|
||||||
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case RawAst.Tree.Type.Ident: {
|
case RawAst.Tree.Type.Ident: {
|
||||||
@ -408,6 +420,14 @@ class Abstractor {
|
|||||||
throw new Error('Unreachable: Splice in non-interpolated text field')
|
throw new Error('Unreachable: Splice in non-interpolated text field')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private abstractTypeSignature(signature: RawAst.TypeSignature) {
|
||||||
|
return {
|
||||||
|
name: this.abstractTree(signature.name),
|
||||||
|
operator: this.abstractToken(signature.operator),
|
||||||
|
type: this.abstractTree(signature.typeNode),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const nodeKeyBrand: unique symbol
|
declare const nodeKeyBrand: unique symbol
|
||||||
|
@ -449,6 +449,8 @@ type StructuralField<T extends TreeRefs = RawRefs> =
|
|||||||
| TextElement<T>
|
| TextElement<T>
|
||||||
| ArgumentDefinition<T>
|
| ArgumentDefinition<T>
|
||||||
| VectorElement<T>
|
| VectorElement<T>
|
||||||
|
| TypeSignature<T>
|
||||||
|
| SignatureLine<T>
|
||||||
|
|
||||||
/** Type whose fields are all suitable for storage as `Ast` fields. */
|
/** Type whose fields are all suitable for storage as `Ast` fields. */
|
||||||
interface FieldObject<T extends TreeRefs> {
|
interface FieldObject<T extends TreeRefs> {
|
||||||
@ -566,6 +568,10 @@ function mapRefs<T extends TreeRefs, U extends TreeRefs>(
|
|||||||
field: VectorElement<T>,
|
field: VectorElement<T>,
|
||||||
f: MapRef<T, U>,
|
f: MapRef<T, U>,
|
||||||
): VectorElement<U>
|
): VectorElement<U>
|
||||||
|
function mapRefs<T extends TreeRefs, U extends TreeRefs>(
|
||||||
|
field: SignatureLine<T>,
|
||||||
|
f: MapRef<T, U>,
|
||||||
|
): SignatureLine<U>
|
||||||
function mapRefs<T extends TreeRefs, U extends TreeRefs>(
|
function mapRefs<T extends TreeRefs, U extends TreeRefs>(
|
||||||
field: FieldData<T>,
|
field: FieldData<T>,
|
||||||
f: MapRef<T, U>,
|
f: MapRef<T, U>,
|
||||||
@ -2029,7 +2035,19 @@ interface ArgumentType<T extends TreeRefs = RawRefs> {
|
|||||||
type: T['ast']
|
type: T['ast']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TypeSignature<T extends TreeRefs = RawRefs> {
|
||||||
|
name: T['ast']
|
||||||
|
operator: T['token']
|
||||||
|
type: T['ast']
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SignatureLine<T extends TreeRefs = RawRefs> {
|
||||||
|
signature: TypeSignature<T>
|
||||||
|
newlines: T['token'][]
|
||||||
|
}
|
||||||
|
|
||||||
export interface FunctionFields {
|
export interface FunctionFields {
|
||||||
|
signatureLine: SignatureLine | undefined
|
||||||
private_: NodeChild<SyncTokenId> | undefined
|
private_: NodeChild<SyncTokenId> | undefined
|
||||||
name: NodeChild<AstId>
|
name: NodeChild<AstId>
|
||||||
argumentDefinitions: ArgumentDefinition[]
|
argumentDefinitions: ArgumentDefinition[]
|
||||||
@ -2068,6 +2086,7 @@ export class Function extends Ast {
|
|||||||
/** TODO: Add docs */
|
/** TODO: Add docs */
|
||||||
static concrete(
|
static concrete(
|
||||||
module: MutableModule,
|
module: MutableModule,
|
||||||
|
signatureLine: SignatureLine<OwnedRefs> | undefined,
|
||||||
private_: NodeChild<Token> | undefined,
|
private_: NodeChild<Token> | undefined,
|
||||||
name: NodeChild<Owned>,
|
name: NodeChild<Owned>,
|
||||||
argumentDefinitions: ArgumentDefinition<OwnedRefs>[],
|
argumentDefinitions: ArgumentDefinition<OwnedRefs>[],
|
||||||
@ -2077,6 +2096,7 @@ export class Function extends Ast {
|
|||||||
const base = module.baseObject('Function')
|
const base = module.baseObject('Function')
|
||||||
const id_ = base.get('id')
|
const id_ = base.get('id')
|
||||||
const fields = composeFieldData(base, {
|
const fields = composeFieldData(base, {
|
||||||
|
signatureLine: signatureLine && mapRefs(signatureLine, ownedToRaw(module, id_)),
|
||||||
private_,
|
private_,
|
||||||
name: concreteChild(module, name, id_),
|
name: concreteChild(module, name, id_),
|
||||||
argumentDefinitions: argumentDefinitions.map(def => mapRefs(def, ownedToRaw(module, id_))),
|
argumentDefinitions: argumentDefinitions.map(def => mapRefs(def, ownedToRaw(module, id_))),
|
||||||
@ -2099,6 +2119,7 @@ export class Function extends Ast {
|
|||||||
return MutableFunction.concrete(
|
return MutableFunction.concrete(
|
||||||
module,
|
module,
|
||||||
undefined,
|
undefined,
|
||||||
|
undefined,
|
||||||
unspaced(Ident.newAllowingOperators(module, name)),
|
unspaced(Ident.newAllowingOperators(module, name)),
|
||||||
argumentDefinitions,
|
argumentDefinitions,
|
||||||
spaced(makeEquals()),
|
spaced(makeEquals()),
|
||||||
@ -2140,7 +2161,15 @@ export class Function extends Ast {
|
|||||||
|
|
||||||
/** TODO: Add docs */
|
/** TODO: Add docs */
|
||||||
*concreteChildren(_verbatim?: boolean): IterableIterator<RawNodeChild> {
|
*concreteChildren(_verbatim?: boolean): IterableIterator<RawNodeChild> {
|
||||||
const { private_, name, argumentDefinitions, equals, body } = getAll(this.fields)
|
const { signatureLine, private_, name, argumentDefinitions, equals, body } = getAll(this.fields)
|
||||||
|
if (signatureLine) {
|
||||||
|
const { signature, newlines } = signatureLine
|
||||||
|
const { name, operator, type } = signature
|
||||||
|
yield name
|
||||||
|
yield operator
|
||||||
|
yield type
|
||||||
|
yield* newlines
|
||||||
|
}
|
||||||
if (private_) yield private_
|
if (private_) yield private_
|
||||||
yield name
|
yield name
|
||||||
for (const def of argumentDefinitions) {
|
for (const def of argumentDefinitions) {
|
||||||
|
@ -322,6 +322,7 @@ public class ErrorCompilerTest extends CompilerTests {
|
|||||||
parse(
|
parse(
|
||||||
"""
|
"""
|
||||||
fan_out_to_columns : Table -> Text | Integer -> (Any -> Vector Any) -> | Nothing -> Problem_Behavior -> Table | Nothing
|
fan_out_to_columns : Table -> Text | Integer -> (Any -> Vector Any) -> | Nothing -> Problem_Behavior -> Table | Nothing
|
||||||
|
fan_out_to_columns table text_or_integer any_to_vector_any wat problem_behavior = Nothing
|
||||||
""");
|
""");
|
||||||
assertSingleSyntaxError(
|
assertSingleSyntaxError(
|
||||||
ir, Syntax.UnexpectedExpression$.MODULE$, "Unexpected expression", 48, 119);
|
ir, Syntax.UnexpectedExpression$.MODULE$, "Unexpected expression", 48, 119);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.enso.compiler.core;
|
package org.enso.compiler.core;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -41,7 +42,8 @@ import org.enso.syntax2.Parser;
|
|||||||
import org.enso.syntax2.TextElement;
|
import org.enso.syntax2.TextElement;
|
||||||
import org.enso.syntax2.Token;
|
import org.enso.syntax2.Token;
|
||||||
import org.enso.syntax2.Tree;
|
import org.enso.syntax2.Tree;
|
||||||
import org.enso.syntax2.Tree.Invalid;
|
import org.enso.syntax2.TypeSignature;
|
||||||
|
import org.enso.syntax2.TypeSignatureLine;
|
||||||
|
|
||||||
import scala.Option;
|
import scala.Option;
|
||||||
import scala.collection.immutable.LinearSeq;
|
import scala.collection.immutable.LinearSeq;
|
||||||
@ -90,62 +92,60 @@ final class TreeToIr {
|
|||||||
* {@link Option#empty()}.
|
* {@link Option#empty()}.
|
||||||
*/
|
*/
|
||||||
Option<Expression> translateInline(Tree.BodyBlock ast) {
|
Option<Expression> translateInline(Tree.BodyBlock ast) {
|
||||||
List<Expression> expressions = nil();
|
var expressions = new ArrayList<Expression>();
|
||||||
java.util.List<IdentifiedLocation> locations = new ArrayList<>();
|
|
||||||
for (Line statement : ast.getStatements()) {
|
for (Line statement : ast.getStatements()) {
|
||||||
Tree exprTree = statement.getExpression();
|
Tree exprTree = statement.getExpression();
|
||||||
Expression expr = switch (exprTree) {
|
switch (exprTree) {
|
||||||
case null -> null;
|
case null -> {}
|
||||||
case Tree.Export x -> null;
|
case Tree.Export x -> {}
|
||||||
case Tree.Import x -> null;
|
case Tree.Import x -> {}
|
||||||
case Tree.Invalid x -> null;
|
case Tree.Invalid x -> {}
|
||||||
case Tree.TypeSignature sig -> {
|
case Tree.TypeSignatureDeclaration sigDeclaration -> {
|
||||||
Expression methodReference;
|
Expression sigIr;
|
||||||
try {
|
try {
|
||||||
methodReference = translateMethodReference(sig.getVariable(), true);
|
sigIr = (Expression)translateMethodTypeSignature(sigDeclaration.getSignature());
|
||||||
} catch (SyntaxException ex) {
|
} catch (SyntaxException ex) {
|
||||||
methodReference = ex.toError();
|
sigIr = ex.toError();
|
||||||
}
|
}
|
||||||
var signature = translateType(sig.getType());
|
expressions.add(sigIr);
|
||||||
yield new Type.Ascription(
|
|
||||||
methodReference,
|
|
||||||
signature,
|
|
||||||
Option.empty(),
|
|
||||||
getIdentifiedLocation(sig),
|
|
||||||
meta());
|
|
||||||
}
|
|
||||||
case Tree.TypeAnnotated anno -> translateTypeAnnotated(anno);
|
|
||||||
default -> translateExpression(exprTree);
|
|
||||||
};
|
|
||||||
if (expr != null) {
|
|
||||||
expressions = join(expr, expressions);
|
|
||||||
if (expr.location().isDefined()) {
|
|
||||||
locations.add(expr.location().get());
|
|
||||||
}
|
}
|
||||||
|
case Tree.TypeAnnotated anno -> expressions.add(translateTypeAnnotated(anno));
|
||||||
|
default -> translateBlockStatement(exprTree, expressions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return switch (expressions.size()) {
|
return switch (expressions.size()) {
|
||||||
case 0 -> Option.empty();
|
case 0 -> Option.empty();
|
||||||
case 1 -> Option.apply(expressions.head());
|
case 1 -> Option.apply(expressions.get(0));
|
||||||
default -> {
|
default -> {
|
||||||
IdentifiedLocation combinedLocation;
|
IdentifiedLocation firstLocation = null;
|
||||||
if (locations.isEmpty()) {
|
for (var expr : expressions) {
|
||||||
combinedLocation = null;
|
if (expr.location().isDefined()) {
|
||||||
} else {
|
firstLocation = expr.location().get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IdentifiedLocation lastLocation = null;
|
||||||
|
for (var i = expressions.size() - 1; i >= 0; i--) {
|
||||||
|
if (expressions.get(i).location().isDefined()) {
|
||||||
|
lastLocation = expressions.get(i).location().get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IdentifiedLocation combinedLocation = null;
|
||||||
|
if (firstLocation != null && lastLocation != null) {
|
||||||
combinedLocation =
|
combinedLocation =
|
||||||
new IdentifiedLocation(
|
new IdentifiedLocation(
|
||||||
new Location(
|
new Location(firstLocation.start(), lastLocation.end()),
|
||||||
locations.get(1).start(),
|
|
||||||
locations.get(locations.size() - 1).end()
|
|
||||||
),
|
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
var returnValue = expressions.head();
|
Expression returnValue = null;
|
||||||
@SuppressWarnings("unchecked")
|
if (!expressions.isEmpty()) {
|
||||||
var statements = ((List<Expression>) expressions.tail()).reverse();
|
returnValue = expressions.get(expressions.size() - 1);
|
||||||
|
expressions.remove(expressions.size() - 1);
|
||||||
|
}
|
||||||
yield Option.apply(new Expression.Block(
|
yield Option.apply(new Expression.Block(
|
||||||
statements,
|
CollectionConverters.asScala(expressions.iterator()).toList(),
|
||||||
returnValue,
|
returnValue,
|
||||||
combinedLocation,
|
combinedLocation,
|
||||||
false,
|
false,
|
||||||
@ -242,10 +242,7 @@ final class TreeToIr {
|
|||||||
yield join(type, appendTo);
|
yield join(type, appendTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Tree.Function fn -> {
|
case Tree.Function fn -> translateMethodBinding(fn, appendTo);
|
||||||
var binding = translateMethodBinding(fn);
|
|
||||||
yield join(binding, appendTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
||||||
var name = fn.getName();
|
var name = fn.getName();
|
||||||
@ -290,11 +287,8 @@ final class TreeToIr {
|
|||||||
yield translateModuleSymbol(doc.getExpression(), join(comment, appendTo));
|
yield translateModuleSymbol(doc.getExpression(), join(comment, appendTo));
|
||||||
}
|
}
|
||||||
|
|
||||||
case Tree.TypeSignature sig -> {
|
case Tree.TypeSignatureDeclaration sig -> {
|
||||||
var methodReference = translateMethodReference(sig.getVariable(), true);
|
var ascription = translateMethodTypeSignature(sig.getSignature());
|
||||||
var signature = translateType(sig.getType());
|
|
||||||
var ascription = new Type.Ascription(methodReference, signature, Option.empty(),
|
|
||||||
getIdentifiedLocation(sig), meta());
|
|
||||||
yield join(ascription, appendTo);
|
yield join(ascription, appendTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,20 +357,9 @@ final class TreeToIr {
|
|||||||
yield join(ir, appendTo);
|
yield join(ir, appendTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Tree.TypeSignature sig -> {
|
case Tree.TypeSignatureDeclaration sig -> join(translateTypeSignature(sig.getSignature()), appendTo);
|
||||||
var isMethod = false;
|
|
||||||
if (sig.getVariable() instanceof Tree.Ident ident) {
|
|
||||||
isMethod = ident.getToken().isOperatorLexically();
|
|
||||||
}
|
|
||||||
var typeName = translateExpression(sig.getVariable(), isMethod);
|
|
||||||
var ir = translateTypeSignature(sig, sig.getType(), typeName);
|
|
||||||
yield join(ir, appendTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Tree.Function fun -> {
|
case Tree.Function fun -> translateTypeMethodBinding(fun, appendTo);
|
||||||
var ir = translateFunction(fun);
|
|
||||||
yield join(ir, appendTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
||||||
var name = buildName(fn.getName());
|
var name = buildName(fn.getName());
|
||||||
@ -472,8 +455,11 @@ final class TreeToIr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Definition translateMethodBinding(Tree.Function fn)
|
private List<Definition> translateMethodBinding(Tree.Function fn, List<Definition> appendTo)
|
||||||
throws SyntaxException {
|
throws SyntaxException {
|
||||||
|
if (fn.getSignatureLine() instanceof TypeSignatureLine sigLine) {
|
||||||
|
appendTo = join(translateMethodTypeSignature(sigLine.getSignature()), appendTo);
|
||||||
|
}
|
||||||
var methodRef = translateMethodReference(fn.getName(), false);
|
var methodRef = translateMethodReference(fn.getName(), false);
|
||||||
var args = translateArgumentsDefinition(fn.getArgs());
|
var args = translateArgumentsDefinition(fn.getArgs());
|
||||||
var isPrivate = fn.getPrivate() != null;
|
var isPrivate = fn.getPrivate() != null;
|
||||||
@ -492,14 +478,35 @@ final class TreeToIr {
|
|||||||
|
|
||||||
String functionName = fn.getName().codeRepr();
|
String functionName = fn.getName().codeRepr();
|
||||||
var ascribedBody = addTypeAscription(functionName, body, returnSignature, loc);
|
var ascribedBody = addTypeAscription(functionName, body, returnSignature, loc);
|
||||||
return new Method.Binding(
|
return join(new Method.Binding(
|
||||||
methodRef,
|
methodRef,
|
||||||
args,
|
args,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
ascribedBody,
|
ascribedBody,
|
||||||
loc,
|
loc,
|
||||||
meta()
|
meta()
|
||||||
);
|
), appendTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IR> translateTypeMethodBinding(Tree.Function fun, List<IR> appendTo) {
|
||||||
|
if (fun.getSignatureLine() instanceof TypeSignatureLine sigLine) {
|
||||||
|
appendTo = join(translateTypeSignature(sigLine.getSignature()), appendTo);
|
||||||
|
}
|
||||||
|
return join(translateFunction(fun), appendTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Definition translateTypeSignature(TypeSignature sig) {
|
||||||
|
var name = sig.getName();
|
||||||
|
var isMethod = name instanceof Tree.Ident ident && ident.getToken().isOperatorLexically();
|
||||||
|
var fnName = translateExpression(name, isMethod);
|
||||||
|
var fnType = translateType(sig.getType());
|
||||||
|
return new Type.Ascription(fnName, fnType, Option.empty(), getIdentifiedLocation(sig), meta());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Definition translateMethodTypeSignature(TypeSignature sig) throws SyntaxException {
|
||||||
|
var methodReference = translateMethodReference(sig.getName(), true);
|
||||||
|
var signature = translateType(sig.getType());
|
||||||
|
return new Type.Ascription(methodReference, signature, Option.empty(), getIdentifiedLocation(sig), meta());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression translateFunction(Tree.Function fun) {
|
private Expression translateFunction(Tree.Function fun) {
|
||||||
@ -568,11 +575,6 @@ final class TreeToIr {
|
|||||||
return new Type.Ascription(body, type, Option.apply(comment), loc, meta());
|
return new Type.Ascription(body, type, Option.apply(comment), loc, meta());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type.Ascription translateTypeSignature(Tree sig, Tree type, Expression typeName) {
|
|
||||||
var fn = translateType(type);
|
|
||||||
return new Type.Ascription(typeName, fn, Option.empty(), getIdentifiedLocation(sig), meta());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates a method reference from [[AST]] into [[IR]].
|
* Translates a method reference from [[AST]] into [[IR]].
|
||||||
@ -607,7 +609,7 @@ final class TreeToIr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Expression translateCall(Tree ast, boolean isMethod) throws SyntaxException {
|
private Expression translateCall(Tree ast, boolean isMethod) throws SyntaxException {
|
||||||
var args = new java.util.ArrayList<CallArgument>();
|
var args = new ArrayList<CallArgument>();
|
||||||
var hasDefaultsSuspended = false;
|
var hasDefaultsSuspended = false;
|
||||||
var tree = ast;
|
var tree = ast;
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
@ -899,14 +901,7 @@ final class TreeToIr {
|
|||||||
yield new Application.Prefix(fn, args.reverse(), false, getIdentifiedLocation(tree), meta());
|
yield new Application.Prefix(fn, args.reverse(), false, getIdentifiedLocation(tree), meta());
|
||||||
}
|
}
|
||||||
case Tree.BodyBlock body -> translateBodyBlock(body, false);
|
case Tree.BodyBlock body -> translateBodyBlock(body, false);
|
||||||
case Tree.Assignment assign -> {
|
case Tree.Assignment assign -> translateAssignment(assign);
|
||||||
var name = buildNameOrQualifiedName(assign.getPattern());
|
|
||||||
var expr = translateExpression(assign.getExpr(), false);
|
|
||||||
if (expr == null) {
|
|
||||||
expr = translateSyntaxError(assign, Syntax.UnexpectedExpression$.MODULE$);
|
|
||||||
}
|
|
||||||
yield new Expression.Binding(name, expr, getIdentifiedLocation(tree), meta());
|
|
||||||
}
|
|
||||||
case Tree.ArgumentBlockApplication body -> {
|
case Tree.ArgumentBlockApplication body -> {
|
||||||
List<Expression> expressions = nil();
|
List<Expression> expressions = nil();
|
||||||
Expression last = null;
|
Expression last = null;
|
||||||
@ -1013,18 +1008,6 @@ final class TreeToIr {
|
|||||||
case null ->
|
case null ->
|
||||||
translateSyntaxError(tree, new Syntax.UnsupportedSyntax("Strange unary -"));
|
translateSyntaxError(tree, new Syntax.UnsupportedSyntax("Strange unary -"));
|
||||||
};
|
};
|
||||||
case Tree.TypeSignature sig -> {
|
|
||||||
var methodName = buildName(sig.getVariable());
|
|
||||||
var methodReference = new CallArgument.Specified(
|
|
||||||
Option.empty(),
|
|
||||||
methodName,
|
|
||||||
methodName.identifiedLocation(),
|
|
||||||
meta()
|
|
||||||
);
|
|
||||||
var opName = buildName(null, sig.getOperator(), true);
|
|
||||||
var signature = translateTypeCallArgument(sig.getType());
|
|
||||||
yield new Operator.Binary(methodReference, opName, signature, getIdentifiedLocation(sig), meta());
|
|
||||||
}
|
|
||||||
case Tree.TemplateFunction templ -> translateExpression(templ.getAst(), false);
|
case Tree.TemplateFunction templ -> translateExpression(templ.getAst(), false);
|
||||||
case Tree.Wildcard wild -> new Name.Blank(getIdentifiedLocation(wild), meta());
|
case Tree.Wildcard wild -> new Name.Blank(getIdentifiedLocation(wild), meta());
|
||||||
case Tree.AnnotatedBuiltin anno -> {
|
case Tree.AnnotatedBuiltin anno -> {
|
||||||
@ -1058,37 +1041,39 @@ final class TreeToIr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Expression translateTypeSignatureToOprApp(TypeSignature sig) {
|
||||||
|
Name.Literal methodName;
|
||||||
|
try {
|
||||||
|
methodName = buildName(sig.getName());
|
||||||
|
} catch (SyntaxException ex) {
|
||||||
|
return ex.toError();
|
||||||
|
}
|
||||||
|
var methodReference = new CallArgument.Specified(
|
||||||
|
Option.empty(),
|
||||||
|
methodName,
|
||||||
|
methodName.identifiedLocation(),
|
||||||
|
meta()
|
||||||
|
);
|
||||||
|
var opName = buildName(null, sig.getOperator(), true);
|
||||||
|
var signature = translateTypeCallArgument(sig.getType());
|
||||||
|
return new Operator.Binary(methodReference, opName, signature, getIdentifiedLocation(sig), meta());
|
||||||
|
}
|
||||||
|
|
||||||
private Expression.Block translateBodyBlock(Tree.BodyBlock body, boolean suspended) {
|
private Expression.Block translateBodyBlock(Tree.BodyBlock body, boolean suspended) {
|
||||||
var expressions = new java.util.ArrayList<Expression>();
|
var expressions = new ArrayList<Expression>();
|
||||||
Expression last = null;
|
|
||||||
for (var line : body.getStatements()) {
|
for (var line : body.getStatements()) {
|
||||||
Tree expr = line.getExpression();
|
Tree expr = line.getExpression();
|
||||||
if (expr == null) {
|
if (expr != null) {
|
||||||
continue;
|
translateBlockStatement(expr, expressions);
|
||||||
}
|
}
|
||||||
if (last != null) {
|
|
||||||
expressions.add(last);
|
|
||||||
}
|
|
||||||
while (expr instanceof Tree.Documented doc) {
|
|
||||||
expr = doc.getExpression();
|
|
||||||
Expression commentIr;
|
|
||||||
try {
|
|
||||||
commentIr = translateComment(doc, doc.getDocumentation());
|
|
||||||
} catch (SyntaxException ex) {
|
|
||||||
commentIr = ex.toError();
|
|
||||||
}
|
|
||||||
expressions.add(commentIr);
|
|
||||||
}
|
|
||||||
last = translateExpression(expr, false);
|
|
||||||
}
|
}
|
||||||
var locationWithANewLine = getIdentifiedLocation(body, 0, 0, null);
|
var locationWithANewLine = getIdentifiedLocation(body, 0, 0, null);
|
||||||
if (last == null) {
|
Expression last;
|
||||||
if (expressions.isEmpty()) {
|
if (expressions.isEmpty()) {
|
||||||
last = new Empty(locationWithANewLine, meta());
|
last = new Empty(locationWithANewLine, meta());
|
||||||
} else {
|
} else {
|
||||||
last = expressions.get(expressions.size() - 1);
|
last = expressions.get(expressions.size() - 1);
|
||||||
expressions.remove(expressions.size() - 1);
|
expressions.remove(expressions.size() - 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var list = CollectionConverters.asScala(expressions.iterator()).toList();
|
var list = CollectionConverters.asScala(expressions.iterator()).toList();
|
||||||
if (last != null
|
if (last != null
|
||||||
@ -1102,6 +1087,54 @@ final class TreeToIr {
|
|||||||
return new Expression.Block(list, last, locationWithANewLine, suspended, meta());
|
return new Expression.Block(list, last, locationWithANewLine, suspended, meta());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Translate a statement in the body of function. */
|
||||||
|
private void translateBlockStatement(Tree tree, Collection<Expression> appendTo) {
|
||||||
|
switch (tree) {
|
||||||
|
case null -> {}
|
||||||
|
case Tree.Assignment assign -> {
|
||||||
|
appendTo.add(translateAssignment(assign));
|
||||||
|
}
|
||||||
|
case Tree.Function fun -> {
|
||||||
|
if (fun.getSignatureLine() instanceof TypeSignatureLine sigLine) {
|
||||||
|
appendTo.add(translateTypeSignatureToOprApp(sigLine.getSignature()));
|
||||||
|
}
|
||||||
|
appendTo.add(translateFunction(fun));
|
||||||
|
}
|
||||||
|
case Tree.TypeSignatureDeclaration sig -> {
|
||||||
|
appendTo.add(translateTypeSignatureToOprApp(sig.getSignature()));
|
||||||
|
}
|
||||||
|
case Tree.Documented doc -> {
|
||||||
|
Expression ir;
|
||||||
|
try {
|
||||||
|
ir = translateComment(doc, doc.getDocumentation());
|
||||||
|
} catch (SyntaxException ex) {
|
||||||
|
ir = ex.toError();
|
||||||
|
}
|
||||||
|
appendTo.add(ir);
|
||||||
|
translateBlockStatement(doc.getExpression(), appendTo);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
var expressionStatement = translateExpression(tree);
|
||||||
|
if (expressionStatement != null) {
|
||||||
|
appendTo.add(expressionStatement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression translateAssignment(Tree.Assignment assign) {
|
||||||
|
try {
|
||||||
|
var name = buildNameOrQualifiedName(assign.getPattern());
|
||||||
|
var expr = translateExpression(assign.getExpr(), false);
|
||||||
|
if (expr == null) {
|
||||||
|
expr = translateSyntaxError(assign, Syntax.UnexpectedExpression$.MODULE$);
|
||||||
|
}
|
||||||
|
return new Expression.Binding(name, expr, getIdentifiedLocation(assign), meta());
|
||||||
|
} catch (SyntaxException ex) {
|
||||||
|
return ex.toError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void attachTranslatedWarnings(IR ir, Tree tree) {
|
private void attachTranslatedWarnings(IR ir, Tree tree) {
|
||||||
for (var warning : tree.getWarnings()) {
|
for (var warning : tree.getWarnings()) {
|
||||||
var message = Parser.getWarningMessage(warning);
|
var message = Parser.getWarningMessage(warning);
|
||||||
@ -1143,7 +1176,6 @@ final class TreeToIr {
|
|||||||
case Tree.Import ignored -> null;
|
case Tree.Import ignored -> null;
|
||||||
case Tree.Export ignored -> null;
|
case Tree.Export ignored -> null;
|
||||||
case Tree.TypeDef ignored -> null;
|
case Tree.TypeDef ignored -> null;
|
||||||
case Tree.TypeSignature ignored -> null;
|
|
||||||
case Tree.ArgumentBlockApplication app -> app.getLhs();
|
case Tree.ArgumentBlockApplication app -> app.getLhs();
|
||||||
case Tree.OperatorBlockApplication app -> app.getLhs();
|
case Tree.OperatorBlockApplication app -> app.getLhs();
|
||||||
case Tree.OprApp app -> app.getLhs();
|
case Tree.OprApp app -> app.getLhs();
|
||||||
@ -1570,7 +1602,7 @@ final class TreeToIr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private java.util.List<Tree> unrollOprRhs(Tree list, String operator) throws SyntaxException {
|
private java.util.List<Tree> unrollOprRhs(Tree list, String operator) throws SyntaxException {
|
||||||
var segments = new java.util.ArrayList<Tree>();
|
var segments = new ArrayList<Tree>();
|
||||||
while (list instanceof Tree.OprApp) {
|
while (list instanceof Tree.OprApp) {
|
||||||
var app = (Tree.OprApp) list;
|
var app = (Tree.OprApp) list;
|
||||||
if (app.getOpr().getRight() == null || !operator.equals(app.getOpr().getRight().codeRepr())) {
|
if (app.getOpr().getRight() == null || !operator.equals(app.getOpr().getRight().codeRepr())) {
|
||||||
@ -1593,7 +1625,7 @@ final class TreeToIr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private java.util.List<Tree> unrollApp(Tree list) {
|
private java.util.List<Tree> unrollApp(Tree list) {
|
||||||
var elems = new java.util.ArrayList<Tree>();
|
var elems = new ArrayList<Tree>();
|
||||||
while (list instanceof Tree.App app) {
|
while (list instanceof Tree.App app) {
|
||||||
elems.add(app.getArg());
|
elems.add(app.getArg());
|
||||||
list = app.getFunc();
|
list = app.getFunc();
|
||||||
@ -1694,7 +1726,7 @@ final class TreeToIr {
|
|||||||
meta()
|
meta()
|
||||||
);
|
);
|
||||||
} catch (SyntaxException err) {
|
} catch (SyntaxException err) {
|
||||||
if (err.where instanceof Invalid invalid) {
|
if (err.where instanceof Tree.Invalid invalid) {
|
||||||
return err.toError(invalidImportReason(invalid.getError()));
|
return err.toError(invalidImportReason(invalid.getError()));
|
||||||
} else {
|
} else {
|
||||||
return err.toError(invalidImportReason(null));
|
return err.toError(invalidImportReason(null));
|
||||||
@ -1758,7 +1790,7 @@ final class TreeToIr {
|
|||||||
meta()
|
meta()
|
||||||
);
|
);
|
||||||
} catch (SyntaxException err) {
|
} catch (SyntaxException err) {
|
||||||
if (err.where instanceof Invalid invalid) {
|
if (err.where instanceof Tree.Invalid invalid) {
|
||||||
return err.toError(invalidExportReason(invalid.getError()));
|
return err.toError(invalidExportReason(invalid.getError()));
|
||||||
} else {
|
} else {
|
||||||
return err.toError(invalidExportReason(null));
|
return err.toError(invalidExportReason(null));
|
||||||
@ -1905,6 +1937,10 @@ final class TreeToIr {
|
|||||||
return new IdentifiedLocation(begin_, end_, uuid);
|
return new IdentifiedLocation(begin_, end_, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IdentifiedLocation getIdentifiedLocation(TypeSignature sig) {
|
||||||
|
return expandToContain(getIdentifiedLocation(sig.getName()), getIdentifiedLocation(sig.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
private IdentifiedLocation getIdentifiedLocation(Token ast) {
|
private IdentifiedLocation getIdentifiedLocation(Token ast) {
|
||||||
return getIdentifiedLocation(ast, false);
|
return getIdentifiedLocation(ast, false);
|
||||||
}
|
}
|
||||||
|
@ -97,9 +97,11 @@ where T: serde::Serialize + Reflect {
|
|||||||
};
|
};
|
||||||
let line = rust_to_meta[&tree::block::Line::reflect().id];
|
let line = rust_to_meta[&tree::block::Line::reflect().id];
|
||||||
let operator_line = rust_to_meta[&tree::block::OperatorLine::reflect().id];
|
let operator_line = rust_to_meta[&tree::block::OperatorLine::reflect().id];
|
||||||
|
let type_signature_line = rust_to_meta[&tree::TypeSignatureLine::reflect().id];
|
||||||
let invalid = rust_to_meta[&tree::Invalid::reflect().id];
|
let invalid = rust_to_meta[&tree::Invalid::reflect().id];
|
||||||
to_s_expr.mapper(line, into_car);
|
to_s_expr.mapper(line, into_car);
|
||||||
to_s_expr.mapper(operator_line, into_car);
|
to_s_expr.mapper(operator_line, into_car);
|
||||||
|
to_s_expr.mapper(type_signature_line, into_car);
|
||||||
to_s_expr.mapper(invalid, strip_invalid);
|
to_s_expr.mapper(invalid, strip_invalid);
|
||||||
to_s_expr.mapper(text_escape_token, simplify_escape);
|
to_s_expr.mapper(text_escape_token, simplify_escape);
|
||||||
tuplify(to_s_expr.value(ast_ty, &value))
|
tuplify(to_s_expr.value(ast_ty, &value))
|
||||||
|
@ -271,9 +271,9 @@ fn type_methods() {
|
|||||||
(TypeDef Problem_Builder #() #(
|
(TypeDef Problem_Builder #() #(
|
||||||
(Documented
|
(Documented
|
||||||
(#((Section " Returns a vector containing all reported problems, aggregated.")) #(()))
|
(#((Section " Returns a vector containing all reported problems, aggregated.")) #(()))
|
||||||
(TypeSignature (Ident build_problemset) ":" (Ident Vector)))
|
,(Function::new("build_problemset", block![(Ident self)])
|
||||||
,(Function::new("build_problemset", block![(Ident self)])
|
.with_sig(sexp![(Ident Vector)])
|
||||||
.with_arg("self")))));
|
.with_arg("self"))))));
|
||||||
test!("[foo., bar.]",
|
test!("[foo., bar.]",
|
||||||
(Array (OprSectionBoundary 1 (OprApp (Ident foo) (Ok ".") ()))
|
(Array (OprSectionBoundary 1 (OprApp (Ident foo) (Ok ".") ()))
|
||||||
#(("," (OprSectionBoundary 1 (OprApp (Ident bar) (Ok ".") ()))))));
|
#(("," (OprSectionBoundary 1 (OprApp (Ident bar) (Ok ".") ()))))));
|
||||||
@ -288,12 +288,15 @@ fn type_operator_methods() {
|
|||||||
" Foo.+ self b = b",
|
" Foo.+ self b = b",
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
(TypeDef Foo #()
|
(TypeDef Foo #()
|
||||||
#((TypeSignature (Ident #"+") ":"
|
#(,(Function::new("+", sexp![(Ident b)])
|
||||||
(OprApp (Ident Foo) (Ok "->") (OprApp (Ident Foo) (Ok "->") (Ident Foo))))
|
.with_sig(sexp![
|
||||||
,(Function::new("+", sexp![(Ident b)]).with_arg("self").with_arg("b"))
|
(OprApp (Ident Foo) (Ok "->") (OprApp (Ident Foo) (Ok "->") (Ident Foo)))])
|
||||||
(TypeSignature (OprApp (Ident Foo) (Ok ".") (Ident #"+")) ":" (Ident Foo))
|
.with_arg("self")
|
||||||
|
.with_arg("b"))
|
||||||
,(Function::named(sexp![(OprApp (Ident Foo) (Ok ".") (Ident #"+"))], sexp![(Ident b)])
|
,(Function::named(sexp![(OprApp (Ident Foo) (Ok ".") (Ident #"+"))], sexp![(Ident b)])
|
||||||
.with_arg("self").with_arg("b")))));
|
.with_sig(sexp![(Ident Foo)])
|
||||||
|
.with_arg("self")
|
||||||
|
.with_arg("b")))));
|
||||||
test!("Any.==", (OprApp (Ident Any) (Ok ".") (Ident #"==")));
|
test!("Any.==", (OprApp (Ident Any) (Ok ".") (Ident #"==")));
|
||||||
expect_invalid_node("x.-y");
|
expect_invalid_node("x.-y");
|
||||||
expect_invalid_node("x.-1");
|
expect_invalid_node("x.-1");
|
||||||
@ -871,7 +874,7 @@ fn method_app_in_minus_unary() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn autoscope_operator() {
|
fn autoscope_operator() {
|
||||||
test_block!("x : ..True", (TypeSignature (Ident x) ":" (AutoscopedIdentifier ".." True)));
|
test!("x : ..True", (TypeSignatureDeclaration ((Ident x) ":" (AutoscopedIdentifier ".." True))));
|
||||||
test_block!("x = ..True", (Assignment (Ident x) (AutoscopedIdentifier ".." True)));
|
test_block!("x = ..True", (Assignment (Ident x) (AutoscopedIdentifier ".." True)));
|
||||||
test_block!("x = f ..True",
|
test_block!("x = f ..True",
|
||||||
(Assignment (Ident x) (App (Ident f) (AutoscopedIdentifier ".." True))));
|
(Assignment (Ident x) (App (Ident f) (AutoscopedIdentifier ".." True))));
|
||||||
@ -997,13 +1000,21 @@ fn metadata_parsing() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn type_signatures() {
|
fn type_signatures() {
|
||||||
test!("val : Bool", (TypeSignature (Ident val) ":" (Ident Bool)));
|
test!("val : Bool", (TypeSignatureDeclaration ((Ident val) ":" (Ident Bool))));
|
||||||
test!("val : List Int", (TypeSignature (Ident val) ":" (App (Ident List) (Ident Int))));
|
test_block!("val : Bool\nval", (TypeSignatureDeclaration ((Ident val) ":" (Ident Bool))) (Ident val));
|
||||||
|
test_block!("val : Bool", (TypeAnnotated (Ident val) ":" (Ident Bool)));
|
||||||
|
test!("val : Bool\nval = True",
|
||||||
|
,(Function::new("val", sexp![(Ident True)])
|
||||||
|
.with_sig(sexp![(Ident Bool)])));
|
||||||
|
test!("val : Bool\ndifferent_name = True",
|
||||||
|
(TypeSignatureDeclaration ((Ident val) ":" (Ident Bool)))
|
||||||
|
,(Function::new("different_name", sexp![(Ident True)])));
|
||||||
|
test!("val : List Int", (TypeSignatureDeclaration ((Ident val) ":" (App (Ident List) (Ident Int)))));
|
||||||
test!("foo : [Integer | Text] -> (Integer | Text)",
|
test!("foo : [Integer | Text] -> (Integer | Text)",
|
||||||
(TypeSignature (Ident foo) ":"
|
(TypeSignatureDeclaration ((Ident foo) ":"
|
||||||
(OprApp (Array (OprApp (Ident Integer) (Ok "|") (Ident Text)) #())
|
(OprApp (Array (OprApp (Ident Integer) (Ok "|") (Ident Text)) #())
|
||||||
(Ok "->")
|
(Ok "->")
|
||||||
(Group (OprApp (Ident Integer) (Ok "|") (Ident Text))))));
|
(Group (OprApp (Ident Integer) (Ok "|") (Ident Text)))))));
|
||||||
test!("f a (b : Int) : Double",
|
test!("f a (b : Int) : Double",
|
||||||
(TypeAnnotated
|
(TypeAnnotated
|
||||||
(App (App (Ident f) (Ident a)) (Group (TypeAnnotated (Ident b) ":" (Ident Int))))
|
(App (App (Ident f) (Ident a)) (Group (TypeAnnotated (Ident b) ":" (Ident Int))))
|
||||||
@ -1028,8 +1039,8 @@ fn type_annotations() {
|
|||||||
":"
|
":"
|
||||||
(App (Ident My_Type) (TemplateFunction 1 (Wildcard 0))))));
|
(App (Ident My_Type) (TemplateFunction 1 (Wildcard 0))))));
|
||||||
test!("x : List Int -> Int",
|
test!("x : List Int -> Int",
|
||||||
(TypeSignature (Ident x) ":"
|
(TypeSignatureDeclaration ((Ident x) ":"
|
||||||
(OprApp (App (Ident List) (Ident Int)) (Ok "->") (Ident Int))));
|
(OprApp (App (Ident List) (Ident Int)) (Ok "->") (Ident Int)))));
|
||||||
test!("p:Plus + m:Plus",
|
test!("p:Plus + m:Plus",
|
||||||
(OprApp (TypeAnnotated (Ident p) ":" (Ident Plus))
|
(OprApp (TypeAnnotated (Ident p) ":" (Ident Plus))
|
||||||
(Ok "+") (TypeAnnotated (Ident m) ":" (Ident Plus))));
|
(Ok "+") (TypeAnnotated (Ident m) ":" (Ident Plus))));
|
||||||
@ -1476,9 +1487,9 @@ fn attributes() {
|
|||||||
(Annotated on_problems
|
(Annotated on_problems
|
||||||
(OprApp (Ident P) (Ok ".") (Ident g))
|
(OprApp (Ident P) (Ok ".") (Ident g))
|
||||||
#(())
|
#(())
|
||||||
(TypeSignature (OprApp (Ident Table) (Ok ".") (Ident select_columns))
|
(TypeSignatureDeclaration ((OprApp (Ident Table) (Ok ".") (Ident select_columns))
|
||||||
":"
|
":"
|
||||||
(OprApp (Ident Text) (Ok "->") (Ident Table)))));
|
(OprApp (Ident Text) (Ok "->") (Ident Table))))));
|
||||||
test!("@a z\n@b\nx", (Annotated a (Ident z) #(()) (Annotated b () #(()) (Ident x))));
|
test!("@a z\n@b\nx", (Annotated a (Ident z) #(()) (Annotated b () #(()) (Ident x))));
|
||||||
test!("@a\n@b\nx", (Annotated a () #(()) (Annotated b () #(()) (Ident x))));
|
test!("@a\n@b\nx", (Annotated a () #(()) (Annotated b () #(()) (Ident x))));
|
||||||
}
|
}
|
||||||
@ -1838,11 +1849,12 @@ fn expect_valid(code: &str) {
|
|||||||
|
|
||||||
/// Builder for function definitions.
|
/// Builder for function definitions.
|
||||||
struct Function {
|
struct Function {
|
||||||
private: lexpr::Value,
|
signature: lexpr::Value,
|
||||||
name: lexpr::Value,
|
private: lexpr::Value,
|
||||||
args: Vec<lexpr::Value>,
|
name: lexpr::Value,
|
||||||
body: lexpr::Value,
|
args: Vec<lexpr::Value>,
|
||||||
ret: lexpr::Value,
|
body: lexpr::Value,
|
||||||
|
ret: lexpr::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
@ -1852,7 +1864,13 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn named(name: lexpr::Value, body: lexpr::Value) -> Self {
|
fn named(name: lexpr::Value, body: lexpr::Value) -> Self {
|
||||||
Self { private: sexp![()], name, args: vec![], body, ret: sexp![()] }
|
Self { signature: sexp![()], private: sexp![()], name, args: vec![], body, ret: sexp![()] }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn with_sig(self, signature: lexpr::Value) -> Self {
|
||||||
|
let name = self.name.clone();
|
||||||
|
Self { signature: sexp![(,name ":" ,signature)], ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_arg(mut self, arg: impl Into<Arg>) -> Self {
|
fn with_arg(mut self, arg: impl Into<Arg>) -> Self {
|
||||||
@ -1871,8 +1889,8 @@ impl Function {
|
|||||||
|
|
||||||
impl From<Function> for lexpr::Value {
|
impl From<Function> for lexpr::Value {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn from(Function { private, name, args, ret, body }: Function) -> Self {
|
fn from(Function { signature, private, name, args, ret, body }: Function) -> Self {
|
||||||
sexp![(Function ,private ,name ,args ,ret ,body)]
|
sexp![(Function ,signature ,private ,name ,args ,ret ,body)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,10 +176,11 @@ impl<'s> Finish for ResolverState<'s> {
|
|||||||
|
|
||||||
fn finish(&mut self) -> Self::Result {
|
fn finish(&mut self) -> Self::Result {
|
||||||
self.finish_current_line();
|
self.finish_current_line();
|
||||||
let lines = self.lines.drain(..);
|
|
||||||
let tree = match self.root_context {
|
let tree = match self.root_context {
|
||||||
RootContext::Module => syntax::tree::block::parse_module(lines, &mut self.precedence),
|
RootContext::Module =>
|
||||||
RootContext::Block => syntax::tree::block::parse_block(lines, &mut self.precedence),
|
syntax::tree::block::parse_module(&mut self.lines, &mut self.precedence),
|
||||||
|
RootContext::Block =>
|
||||||
|
syntax::tree::block::parse_block(&mut self.lines, &mut self.precedence),
|
||||||
};
|
};
|
||||||
debug_assert!(self.blocks.is_empty());
|
debug_assert!(self.blocks.is_empty());
|
||||||
debug_assert!(self.lines.is_empty());
|
debug_assert!(self.lines.is_empty());
|
||||||
|
@ -12,14 +12,15 @@ use crate::prelude::*;
|
|||||||
use crate::syntax::item;
|
use crate::syntax::item;
|
||||||
use crate::syntax::maybe_with_error;
|
use crate::syntax::maybe_with_error;
|
||||||
use crate::syntax::operator::Precedence;
|
use crate::syntax::operator::Precedence;
|
||||||
use crate::syntax::statement::function_def::parse_function_decl;
|
|
||||||
use crate::syntax::statement::function_def::try_parse_foreign_function;
|
use crate::syntax::statement::function_def::try_parse_foreign_function;
|
||||||
|
use crate::syntax::statement::function_def::FunctionBuilder;
|
||||||
use crate::syntax::statement::type_def::try_parse_type_def;
|
use crate::syntax::statement::type_def::try_parse_type_def;
|
||||||
use crate::syntax::token;
|
use crate::syntax::token;
|
||||||
use crate::syntax::tree;
|
use crate::syntax::tree;
|
||||||
use crate::syntax::tree::block;
|
use crate::syntax::tree::block;
|
||||||
use crate::syntax::tree::ArgumentDefinition;
|
use crate::syntax::tree::ArgumentDefinition;
|
||||||
use crate::syntax::tree::SyntaxError;
|
use crate::syntax::tree::SyntaxError;
|
||||||
|
use crate::syntax::tree::TypeSignature;
|
||||||
use crate::syntax::treebuilding::Spacing;
|
use crate::syntax::treebuilding::Spacing;
|
||||||
use crate::syntax::Item;
|
use crate::syntax::Item;
|
||||||
use crate::syntax::Token;
|
use crate::syntax::Token;
|
||||||
@ -37,12 +38,15 @@ impl<'s> BodyBlockParser<'s> {
|
|||||||
/// Parse the statements in a block.
|
/// Parse the statements in a block.
|
||||||
pub fn parse_body_block(
|
pub fn parse_body_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
lines: impl IntoIterator<Item = item::Line<'s>>,
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
) -> Tree<'s> {
|
) -> Tree<'s> {
|
||||||
let lines = lines.into_iter().map(|item::Line { newline, mut items }| block::Line {
|
let lines = compound_lines_with_tail_expression(lines, |prefixes, line, is_tail| {
|
||||||
newline,
|
if is_tail {
|
||||||
expression: self.statement_parser.parse_statement(&mut items, 0, precedence),
|
self.statement_parser.parse_tail_expression(line, precedence)
|
||||||
|
} else {
|
||||||
|
self.statement_parser.parse_statement(prefixes, line, precedence)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Tree::body_block(block::compound_lines(lines).collect())
|
Tree::body_block(block::compound_lines(lines).collect())
|
||||||
}
|
}
|
||||||
@ -50,17 +54,100 @@ impl<'s> BodyBlockParser<'s> {
|
|||||||
/// Parse the declarations and statements at the top level of a module.
|
/// Parse the declarations and statements at the top level of a module.
|
||||||
pub fn parse_module(
|
pub fn parse_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
lines: impl IntoIterator<Item = item::Line<'s>>,
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
) -> Tree<'s> {
|
) -> Tree<'s> {
|
||||||
let lines = lines.into_iter().map(|item::Line { newline, mut items }| block::Line {
|
let lines = compound_lines(lines, |prefixes, line| {
|
||||||
newline,
|
self.statement_parser.parse_module_statement(prefixes, line, precedence)
|
||||||
expression: self.statement_parser.parse_module_statement(&mut items, 0, precedence),
|
|
||||||
});
|
});
|
||||||
Tree::body_block(block::compound_lines(lines).collect())
|
Tree::body_block(block::compound_lines(lines).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compound_lines<'s>(
|
||||||
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
|
mut parse_line: impl FnMut(
|
||||||
|
&mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
|
item::Line<'s>,
|
||||||
|
) -> Line<'s, StatementOrPrefix<'s>>,
|
||||||
|
) -> Vec<block::Line<'s>> {
|
||||||
|
compound_lines_maybe_with_tail_expression(
|
||||||
|
lines,
|
||||||
|
|prefixes, line, _| parse_line(prefixes, line),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compound_lines_with_tail_expression<'s>(
|
||||||
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
|
parse_line: impl FnMut(
|
||||||
|
&mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
|
item::Line<'s>,
|
||||||
|
bool,
|
||||||
|
) -> Line<'s, StatementOrPrefix<'s>>,
|
||||||
|
) -> Vec<block::Line<'s>> {
|
||||||
|
compound_lines_maybe_with_tail_expression(
|
||||||
|
lines,
|
||||||
|
parse_line,
|
||||||
|
lines.iter().enumerate().rfind(|(_, prefix)| !prefix.items.is_empty()).map(|(i, _)| i),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compound_lines_maybe_with_tail_expression<'s>(
|
||||||
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
|
mut parse_line: impl FnMut(
|
||||||
|
&mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
|
item::Line<'s>,
|
||||||
|
bool,
|
||||||
|
) -> Line<'s, StatementOrPrefix<'s>>,
|
||||||
|
tail_index: Option<usize>,
|
||||||
|
) -> Vec<block::Line<'s>> {
|
||||||
|
let mut block_lines = Vec::new();
|
||||||
|
let mut line_prefixes = Vec::new();
|
||||||
|
for (i, line) in lines.drain(..).enumerate() {
|
||||||
|
let is_tail = tail_index == Some(i);
|
||||||
|
match parse_line(&mut line_prefixes, line, is_tail) {
|
||||||
|
Line { newline, content: Some(StatementOrPrefix::Statement(statement)) } => {
|
||||||
|
for Line { newline, content } in line_prefixes.drain(..) {
|
||||||
|
block_lines.push(block::Line { newline, expression: content.map(Tree::from) })
|
||||||
|
}
|
||||||
|
block_lines.push(block::Line { newline, expression: Some(statement) })
|
||||||
|
}
|
||||||
|
Line { newline, content: Some(StatementOrPrefix::Prefix(prefix)) } =>
|
||||||
|
line_prefixes.push(Line { newline, content: Some(prefix) }),
|
||||||
|
Line { newline, content: None } =>
|
||||||
|
if line_prefixes.is_empty() {
|
||||||
|
block_lines.push(newline.into());
|
||||||
|
} else {
|
||||||
|
line_prefixes.push(newline.into());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for Line { newline, content } in line_prefixes {
|
||||||
|
block_lines.push(block::Line { newline, expression: content.map(Tree::from) })
|
||||||
|
}
|
||||||
|
block_lines
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Line<'s, T> {
|
||||||
|
newline: token::Newline<'s>,
|
||||||
|
content: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s, T> Line<'s, T> {
|
||||||
|
fn map_content<U>(self, f: impl FnOnce(T) -> U) -> Line<'s, U> {
|
||||||
|
let Line { newline, content } = self;
|
||||||
|
Line { newline, content: content.map(f) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s, T> From<token::Newline<'s>> for Line<'s, T> {
|
||||||
|
fn from(newline: token::Newline<'s>) -> Self {
|
||||||
|
Self { newline, content: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct StatementParser<'s> {
|
struct StatementParser<'s> {
|
||||||
args_buffer: Vec<ArgumentDefinition<'s>>,
|
args_buffer: Vec<ArgumentDefinition<'s>>,
|
||||||
@ -69,33 +156,49 @@ struct StatementParser<'s> {
|
|||||||
impl<'s> StatementParser<'s> {
|
impl<'s> StatementParser<'s> {
|
||||||
fn parse_statement(
|
fn parse_statement(
|
||||||
&mut self,
|
&mut self,
|
||||||
items: &mut Vec<Item<'s>>,
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
start: usize,
|
line: item::Line<'s>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
) -> Option<Tree<'s>> {
|
) -> Line<'s, StatementOrPrefix<'s>> {
|
||||||
parse_statement(items, start, precedence, &mut self.args_buffer, StatementContext {
|
parse_statement(prefixes, line, precedence, &mut self.args_buffer, StatementContext {
|
||||||
evaluation_context: EvaluationContext::Eager,
|
evaluation_context: EvaluationContext::Eager,
|
||||||
visibility_context: VisibilityContext::Private,
|
visibility_context: VisibilityContext::Private,
|
||||||
|
tail_expression: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_tail_expression(
|
||||||
|
&mut self,
|
||||||
|
line: item::Line<'s>,
|
||||||
|
precedence: &mut Precedence<'s>,
|
||||||
|
) -> Line<'s, StatementOrPrefix<'s>> {
|
||||||
|
parse_statement(&mut vec![], line, precedence, &mut self.args_buffer, StatementContext {
|
||||||
|
evaluation_context: EvaluationContext::Eager,
|
||||||
|
visibility_context: VisibilityContext::Private,
|
||||||
|
tail_expression: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_module_statement(
|
fn parse_module_statement(
|
||||||
&mut self,
|
&mut self,
|
||||||
items: &mut Vec<Item<'s>>,
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
start: usize,
|
line: item::Line<'s>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
) -> Option<Tree<'s>> {
|
) -> Line<'s, StatementOrPrefix<'s>> {
|
||||||
parse_statement(items, start, precedence, &mut self.args_buffer, StatementContext {
|
parse_statement(prefixes, line, precedence, &mut self.args_buffer, StatementContext {
|
||||||
evaluation_context: EvaluationContext::Lazy,
|
evaluation_context: EvaluationContext::Lazy,
|
||||||
visibility_context: VisibilityContext::Public,
|
visibility_context: VisibilityContext::Public,
|
||||||
|
tail_expression: false,
|
||||||
})
|
})
|
||||||
.map(|statement| {
|
.map_content(|statement_or_prefix| {
|
||||||
let error = match &statement.variant {
|
statement_or_prefix.map_statement(|statement| {
|
||||||
tree::Variant::Assignment(_) =>
|
let error = match &statement.variant {
|
||||||
SyntaxError::StmtUnexpectedAssignmentInModuleBody.into(),
|
tree::Variant::Assignment(_) =>
|
||||||
_ => None,
|
SyntaxError::StmtUnexpectedAssignmentInModuleBody.into(),
|
||||||
};
|
_ => None,
|
||||||
maybe_with_error(statement, error)
|
};
|
||||||
|
maybe_with_error(statement, error)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,45 +215,92 @@ fn scan_private_keywords<'s>(items: impl IntoIterator<Item = impl AsRef<Item<'s>
|
|||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum StatementPrefix<'s> {
|
||||||
|
TypeSignature(TypeSignature<'s>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> From<StatementPrefix<'s>> for Tree<'s> {
|
||||||
|
fn from(value: StatementPrefix<'s>) -> Self {
|
||||||
|
match value {
|
||||||
|
StatementPrefix::TypeSignature(signature) =>
|
||||||
|
Tree::type_signature_declaration(signature),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StatementOrPrefix<'s> {
|
||||||
|
Statement(Tree<'s>),
|
||||||
|
Prefix(StatementPrefix<'s>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> StatementOrPrefix<'s> {
|
||||||
|
fn map_statement(self, f: impl FnOnce(Tree<'s>) -> Tree<'s>) -> Self {
|
||||||
|
match self {
|
||||||
|
StatementOrPrefix::Statement(statement) => StatementOrPrefix::Statement(f(statement)),
|
||||||
|
prefix => prefix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> From<StatementOrPrefix<'s>> for Tree<'s> {
|
||||||
|
fn from(value: StatementOrPrefix<'s>) -> Self {
|
||||||
|
match value {
|
||||||
|
StatementOrPrefix::Statement(tree) => tree,
|
||||||
|
StatementOrPrefix::Prefix(prefix) => prefix.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> From<Tree<'s>> for StatementOrPrefix<'s> {
|
||||||
|
fn from(value: Tree<'s>) -> Self {
|
||||||
|
StatementOrPrefix::Statement(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_statement<'s>(
|
fn parse_statement<'s>(
|
||||||
items: &mut Vec<Item<'s>>,
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
statement_start: usize,
|
mut line: item::Line<'s>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
||||||
statement_context: StatementContext,
|
statement_context: StatementContext,
|
||||||
) -> Option<Tree<'s>> {
|
) -> Line<'s, StatementOrPrefix<'s>> {
|
||||||
|
let newline = line.newline;
|
||||||
use token::Variant;
|
use token::Variant;
|
||||||
let private_keywords = scan_private_keywords(&items[statement_start..]);
|
let private_keywords = scan_private_keywords(&line.items);
|
||||||
let start = statement_start + private_keywords;
|
let start = private_keywords;
|
||||||
|
let items = &mut line.items;
|
||||||
if let Some(type_def) = try_parse_type_def(items, start, precedence, args_buffer) {
|
if let Some(type_def) = try_parse_type_def(items, start, precedence, args_buffer) {
|
||||||
debug_assert_eq!(items.len(), start);
|
debug_assert_eq!(items.len(), start);
|
||||||
return apply_private_keywords(
|
return Line {
|
||||||
Some(type_def),
|
newline,
|
||||||
items.drain(statement_start..),
|
content: apply_private_keywords(
|
||||||
statement_context.visibility_context,
|
Some(type_def),
|
||||||
);
|
items.drain(..),
|
||||||
|
statement_context.visibility_context,
|
||||||
|
)
|
||||||
|
.map(StatementOrPrefix::Statement),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
let top_level_operator = match find_top_level_operator(&items[start..]) {
|
let top_level_operator = match find_top_level_operator(&items[start..]) {
|
||||||
Ok(top_level_operator) => top_level_operator.map(|(i, t)| (i + start, t)),
|
Ok(top_level_operator) => top_level_operator.map(|(i, t)| (i + start, t)),
|
||||||
Err(e) =>
|
Err(e) =>
|
||||||
return precedence
|
return Line {
|
||||||
.resolve_non_section_offset(statement_start, items)
|
newline,
|
||||||
.unwrap()
|
content: Some(precedence.resolve_non_section(items).unwrap().with_error(e).into()),
|
||||||
.with_error(e)
|
},
|
||||||
.into(),
|
|
||||||
};
|
};
|
||||||
let statement = match top_level_operator {
|
match top_level_operator {
|
||||||
Some((i, Token { variant: Variant::AssignmentOperator(_), .. })) =>
|
Some((i, Token { variant: Variant::AssignmentOperator(_), .. })) =>
|
||||||
parse_assignment_like_statement(
|
parse_assignment_like_statement(
|
||||||
items,
|
prefixes,
|
||||||
statement_start,
|
item::Line { newline, items: mem::take(items) },
|
||||||
start,
|
start,
|
||||||
i,
|
i,
|
||||||
precedence,
|
precedence,
|
||||||
args_buffer,
|
args_buffer,
|
||||||
statement_context,
|
statement_context,
|
||||||
)
|
)
|
||||||
.into(),
|
.map_content(StatementOrPrefix::Statement),
|
||||||
Some((i, Token { variant: Variant::TypeAnnotationOperator(_), .. })) => {
|
Some((i, Token { variant: Variant::TypeAnnotationOperator(_), .. })) => {
|
||||||
let type_ = precedence.resolve_non_section_offset(i + 1, items);
|
let type_ = precedence.resolve_non_section_offset(i + 1, items);
|
||||||
let operator: token::TypeAnnotationOperator =
|
let operator: token::TypeAnnotationOperator =
|
||||||
@ -159,53 +309,77 @@ fn parse_statement<'s>(
|
|||||||
let type_ = type_.unwrap_or_else(|| {
|
let type_ = type_.unwrap_or_else(|| {
|
||||||
empty_tree(operator.code.position_after()).with_error(SyntaxError::ExpectedType)
|
empty_tree(operator.code.position_after()).with_error(SyntaxError::ExpectedType)
|
||||||
});
|
});
|
||||||
if lhs.as_ref().is_some_and(is_qualified_name) {
|
debug_assert!(items.len() <= start);
|
||||||
Tree::type_signature(lhs.unwrap(), operator, type_).into()
|
let statement = Some(
|
||||||
} else {
|
if lhs.as_ref().is_some_and(is_qualified_name) && !statement_context.tail_expression
|
||||||
let lhs = lhs.unwrap_or_else(|| {
|
{
|
||||||
empty_tree(operator.left_offset.code.position_before())
|
StatementOrPrefix::Prefix(StatementPrefix::TypeSignature(TypeSignature {
|
||||||
.with_error(SyntaxError::ExpectedExpression)
|
name: lhs.unwrap(),
|
||||||
});
|
operator,
|
||||||
Tree::type_annotated(lhs, operator, type_).into()
|
type_,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
let lhs = lhs.unwrap_or_else(|| {
|
||||||
|
empty_tree(operator.left_offset.code.position_before())
|
||||||
|
.with_error(SyntaxError::ExpectedExpression)
|
||||||
|
});
|
||||||
|
Tree::type_annotated(lhs, operator, type_).into()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Line {
|
||||||
|
newline,
|
||||||
|
content: apply_private_keywords(
|
||||||
|
statement,
|
||||||
|
items.drain(..),
|
||||||
|
statement_context.visibility_context,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(_) => unreachable!(),
|
Some(_) => unreachable!(),
|
||||||
None => precedence.resolve_offset(start, items),
|
None => {
|
||||||
};
|
let statement = precedence.resolve_offset(start, items);
|
||||||
debug_assert!(items.len() <= start);
|
debug_assert!(items.len() <= start);
|
||||||
apply_private_keywords(
|
Line {
|
||||||
statement,
|
newline,
|
||||||
items.drain(statement_start..),
|
content: apply_private_keywords(
|
||||||
statement_context.visibility_context,
|
statement,
|
||||||
)
|
items.drain(..),
|
||||||
|
statement_context.visibility_context,
|
||||||
|
)
|
||||||
|
.map(StatementOrPrefix::Statement),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply any private keywords that were not already consumed by a statement parser that recognizes
|
/// Apply any private keywords that were not already consumed by a statement parser that recognizes
|
||||||
/// them specifically (such as in a function definition).
|
/// them specifically (such as in a function definition).
|
||||||
fn apply_private_keywords<'s>(
|
fn apply_private_keywords<'s, U: From<Tree<'s>> + Into<Tree<'s>>>(
|
||||||
mut statement: Option<Tree<'s>>,
|
mut statement: Option<U>,
|
||||||
keywords: impl Iterator<Item = Item<'s>>,
|
keywords: impl Iterator<Item = Item<'s>>,
|
||||||
visibility_context: VisibilityContext,
|
visibility_context: VisibilityContext,
|
||||||
) -> Option<Tree<'s>> {
|
) -> Option<U> {
|
||||||
for item in keywords {
|
for item in keywords {
|
||||||
let private = Tree::private(item.into_token().unwrap().try_into().unwrap());
|
let private = Tree::private(item.into_token().unwrap().try_into().unwrap());
|
||||||
statement = match statement.take() {
|
statement = Some(
|
||||||
Some(statement) => Tree::app(
|
match statement.take() {
|
||||||
private.with_error(match visibility_context {
|
Some(statement) => Tree::app(
|
||||||
VisibilityContext::Public => SyntaxError::StmtUnexpectedPrivateSubject,
|
private.with_error(match visibility_context {
|
||||||
VisibilityContext::Private => SyntaxError::StmtUnexpectedPrivateContext,
|
VisibilityContext::Public => SyntaxError::StmtUnexpectedPrivateSubject,
|
||||||
|
VisibilityContext::Private => SyntaxError::StmtUnexpectedPrivateContext,
|
||||||
|
}),
|
||||||
|
statement.into(),
|
||||||
|
),
|
||||||
|
None => maybe_with_error(private, match visibility_context {
|
||||||
|
// This is the only non-error case in this function: A `private` keyword was
|
||||||
|
// found not modifying any other statement, and in a context where a `private`
|
||||||
|
// declaration is allowed; in this case, we emit a `Private` declaration.
|
||||||
|
VisibilityContext::Public => None,
|
||||||
|
VisibilityContext::Private => Some(SyntaxError::StmtUnexpectedPrivateContext),
|
||||||
}),
|
}),
|
||||||
statement,
|
}
|
||||||
),
|
.into(),
|
||||||
None => maybe_with_error(private, match visibility_context {
|
);
|
||||||
// This is the only non-error case in this function: A `private` keyword was found
|
|
||||||
// not modifying any other statement, and in a context where a `private` declaration
|
|
||||||
// is allowed; in this case, we emit a `Private` declaration without error.
|
|
||||||
VisibilityContext::Public => None,
|
|
||||||
VisibilityContext::Private => Some(SyntaxError::StmtUnexpectedPrivateContext),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
.into();
|
|
||||||
}
|
}
|
||||||
statement
|
statement
|
||||||
}
|
}
|
||||||
@ -214,6 +388,7 @@ fn apply_private_keywords<'s>(
|
|||||||
struct StatementContext {
|
struct StatementContext {
|
||||||
evaluation_context: EvaluationContext,
|
evaluation_context: EvaluationContext,
|
||||||
visibility_context: VisibilityContext,
|
visibility_context: VisibilityContext,
|
||||||
|
tail_expression: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
@ -233,19 +408,25 @@ enum VisibilityContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_assignment_like_statement<'s>(
|
fn parse_assignment_like_statement<'s>(
|
||||||
items: &mut Vec<Item<'s>>,
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
private_keywords_start: usize,
|
mut line: item::Line<'s>,
|
||||||
start: usize,
|
start: usize,
|
||||||
operator: usize,
|
operator: usize,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
||||||
StatementContext { evaluation_context, visibility_context }: StatementContext,
|
StatementContext { evaluation_context, visibility_context, .. }: StatementContext,
|
||||||
) -> Tree<'s> {
|
) -> Line<'s, Tree<'s>> {
|
||||||
|
let items = &mut line.items;
|
||||||
|
let newline = line.newline;
|
||||||
if operator == start {
|
if operator == start {
|
||||||
return precedence
|
let error = precedence
|
||||||
.resolve_non_section_offset(start, items)
|
.resolve_non_section_offset(start, items)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_error(SyntaxError::StmtInvalidAssignmentOrMethod);
|
.with_error(SyntaxError::StmtInvalidAssignmentOrMethod);
|
||||||
|
return Line {
|
||||||
|
newline,
|
||||||
|
content: apply_private_keywords(Some(error), items.drain(..), visibility_context),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expression = precedence.resolve_offset(operator + 1, items);
|
let mut expression = precedence.resolve_offset(operator + 1, items);
|
||||||
@ -269,7 +450,10 @@ fn parse_assignment_like_statement<'s>(
|
|||||||
precedence,
|
precedence,
|
||||||
args_buffer,
|
args_buffer,
|
||||||
) {
|
) {
|
||||||
return function;
|
return Line {
|
||||||
|
newline,
|
||||||
|
content: apply_private_keywords(Some(function), items.drain(..), visibility_context),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
let operator = operator.unwrap();
|
let operator = operator.unwrap();
|
||||||
|
|
||||||
@ -288,23 +472,33 @@ fn parse_assignment_like_statement<'s>(
|
|||||||
(expression, Some(qn_len)) => Type::Function { expression, qn_len },
|
(expression, Some(qn_len)) => Type::Function { expression, qn_len },
|
||||||
(None, None) => Type::InvalidNoExpressionNoQn,
|
(None, None) => Type::InvalidNoExpressionNoQn,
|
||||||
} {
|
} {
|
||||||
Type::Assignment { expression } =>
|
Type::Assignment { expression } => Line {
|
||||||
parse_assignment(start, items, operator, expression, precedence),
|
newline,
|
||||||
Type::Function { expression, qn_len } => {
|
content: apply_private_keywords(
|
||||||
let (qn, args, return_) =
|
Some(parse_assignment(start, items, operator, expression, precedence)),
|
||||||
parse_function_decl(items, start, qn_len, precedence, args_buffer);
|
items.drain(..),
|
||||||
let private = (visibility_context != VisibilityContext::Private
|
visibility_context,
|
||||||
&& private_keywords_start < start)
|
),
|
||||||
.then(|| items.pop().unwrap().into_token().unwrap().try_into().unwrap());
|
},
|
||||||
|
Type::Function { expression, qn_len } => FunctionBuilder::new(
|
||||||
Tree::function(private, qn, args, return_, operator, expression)
|
item::Line { newline, items: mem::take(items) },
|
||||||
}
|
start,
|
||||||
Type::InvalidNoExpressionNoQn => Tree::opr_app(
|
qn_len,
|
||||||
precedence.resolve_non_section_offset(start, items),
|
precedence,
|
||||||
Ok(operator.with_variant(token::variant::Operator())),
|
args_buffer,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.with_error(SyntaxError::StmtInvalidAssignmentOrMethod),
|
.build(prefixes, operator, expression, visibility_context),
|
||||||
|
Type::InvalidNoExpressionNoQn => Line {
|
||||||
|
newline,
|
||||||
|
content: Some(
|
||||||
|
Tree::opr_app(
|
||||||
|
precedence.resolve_non_section(items),
|
||||||
|
Ok(operator.with_variant(token::variant::Operator())),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.with_error(SyntaxError::StmtInvalidAssignmentOrMethod),
|
||||||
|
),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,12 @@ use crate::empty_tree;
|
|||||||
use crate::syntax::item;
|
use crate::syntax::item;
|
||||||
use crate::syntax::maybe_with_error;
|
use crate::syntax::maybe_with_error;
|
||||||
use crate::syntax::operator::Precedence;
|
use crate::syntax::operator::Precedence;
|
||||||
|
use crate::syntax::statement::apply_private_keywords;
|
||||||
use crate::syntax::statement::find_top_level_operator;
|
use crate::syntax::statement::find_top_level_operator;
|
||||||
use crate::syntax::statement::parse_pattern;
|
use crate::syntax::statement::parse_pattern;
|
||||||
|
use crate::syntax::statement::Line;
|
||||||
|
use crate::syntax::statement::StatementPrefix;
|
||||||
|
use crate::syntax::statement::VisibilityContext;
|
||||||
use crate::syntax::token;
|
use crate::syntax::token;
|
||||||
use crate::syntax::tree;
|
use crate::syntax::tree;
|
||||||
use crate::syntax::tree::ArgumentDefault;
|
use crate::syntax::tree::ArgumentDefault;
|
||||||
@ -14,6 +18,7 @@ use crate::syntax::tree::ArgumentDefinitionLine;
|
|||||||
use crate::syntax::tree::ArgumentType;
|
use crate::syntax::tree::ArgumentType;
|
||||||
use crate::syntax::tree::ReturnSpecification;
|
use crate::syntax::tree::ReturnSpecification;
|
||||||
use crate::syntax::tree::SyntaxError;
|
use crate::syntax::tree::SyntaxError;
|
||||||
|
use crate::syntax::tree::TypeSignatureLine;
|
||||||
use crate::syntax::treebuilding::Spacing;
|
use crate::syntax::treebuilding::Spacing;
|
||||||
use crate::syntax::Item;
|
use crate::syntax::Item;
|
||||||
use crate::syntax::Token;
|
use crate::syntax::Token;
|
||||||
@ -21,34 +26,114 @@ use crate::syntax::Tree;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_function_decl<'s>(
|
pub struct FunctionBuilder<'s> {
|
||||||
items: &mut Vec<Item<'s>>,
|
name: Tree<'s>,
|
||||||
start: usize,
|
return_: Option<ReturnSpecification<'s>>,
|
||||||
qn_len: usize,
|
args: Vec<ArgumentDefinition<'s>>,
|
||||||
precedence: &mut Precedence<'s>,
|
line: item::Line<'s>,
|
||||||
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
start: usize,
|
||||||
) -> (Tree<'s>, Vec<ArgumentDefinition<'s>>, Option<ReturnSpecification<'s>>) {
|
}
|
||||||
let mut arg_starts = vec![];
|
|
||||||
let mut arrow = None;
|
impl<'s> FunctionBuilder<'s> {
|
||||||
for (i, item) in items.iter().enumerate().skip(start + qn_len) {
|
pub fn new(
|
||||||
if let Item::Token(Token { variant: token::Variant::ArrowOperator(_), .. }) = item {
|
mut line: item::Line<'s>,
|
||||||
arrow = Some(i);
|
start: usize,
|
||||||
break;
|
qn_len: usize,
|
||||||
|
precedence: &mut Precedence<'s>,
|
||||||
|
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut arg_starts = vec![];
|
||||||
|
let mut arrow = None;
|
||||||
|
let items = &mut line.items;
|
||||||
|
for (i, item) in items.iter().enumerate().skip(start + qn_len) {
|
||||||
|
if let Item::Token(Token { variant: token::Variant::ArrowOperator(_), .. }) = item {
|
||||||
|
arrow = Some(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if i == start + qn_len || matches!(Spacing::of_item(item), Spacing::Spaced) {
|
||||||
|
arg_starts.push(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if i == start + qn_len || matches!(Spacing::of_item(item), Spacing::Spaced) {
|
let return_ = arrow.map(|arrow| parse_return_spec(items, arrow, precedence));
|
||||||
arg_starts.push(i);
|
|
||||||
|
args_buffer.extend(
|
||||||
|
arg_starts.drain(..).rev().map(|arg_start| parse_arg_def(items, arg_start, precedence)),
|
||||||
|
);
|
||||||
|
let args = args_buffer.drain(..).rev().collect();
|
||||||
|
|
||||||
|
let name = precedence.resolve_non_section_offset(start, items).unwrap();
|
||||||
|
|
||||||
|
Self { name, return_, args, line, start }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(
|
||||||
|
mut self,
|
||||||
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
|
operator: token::AssignmentOperator<'s>,
|
||||||
|
expression: Option<Tree<'s>>,
|
||||||
|
visibility_context: VisibilityContext,
|
||||||
|
) -> Line<'s, Tree<'s>> {
|
||||||
|
let items = &mut self.line.items;
|
||||||
|
let private_keywords_start = 0;
|
||||||
|
|
||||||
|
let private = (visibility_context != VisibilityContext::Private
|
||||||
|
&& self.start > private_keywords_start)
|
||||||
|
.then(|| items.pop().unwrap().into_token().unwrap().try_into().unwrap());
|
||||||
|
|
||||||
|
let mut first_newline = self.line.newline;
|
||||||
|
let mut signature_line = None;
|
||||||
|
if let Some(Line { content: Some(StatementPrefix::TypeSignature(signature)), .. }) =
|
||||||
|
prefixes.last()
|
||||||
|
{
|
||||||
|
if qn_equivalent(&self.name, &signature.name) {
|
||||||
|
let Some(Line {
|
||||||
|
newline: outer_newline,
|
||||||
|
content: Some(StatementPrefix::TypeSignature(signature)),
|
||||||
|
}) = prefixes.pop()
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let newline = mem::replace(&mut first_newline, outer_newline);
|
||||||
|
signature_line =
|
||||||
|
Some(TypeSignatureLine { signature, newlines: NonEmptyVec::singleton(newline) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Line {
|
||||||
|
newline: first_newline,
|
||||||
|
content: apply_private_keywords(
|
||||||
|
Some(Tree::function(
|
||||||
|
signature_line,
|
||||||
|
private,
|
||||||
|
self.name,
|
||||||
|
self.args,
|
||||||
|
self.return_,
|
||||||
|
operator,
|
||||||
|
expression,
|
||||||
|
)),
|
||||||
|
items.drain(..),
|
||||||
|
visibility_context,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let return_ = arrow.map(|arrow| parse_return_spec(items, arrow, precedence));
|
}
|
||||||
|
|
||||||
args_buffer.extend(
|
fn qn_equivalent(a: &Tree, b: &Tree) -> bool {
|
||||||
arg_starts.drain(..).rev().map(|arg_start| parse_arg_def(items, arg_start, precedence)),
|
use tree::Variant::*;
|
||||||
);
|
match (&a.variant, &b.variant) {
|
||||||
let args = args_buffer.drain(..).rev().collect();
|
(Ident(a), Ident(b)) => a.token.code.repr == b.token.code.repr,
|
||||||
|
(OprApp(a), OprApp(b)) =>
|
||||||
|
opt_qn_equivalent(&a.lhs, &b.lhs) && opt_qn_equivalent(&a.rhs, &b.rhs),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let qn = precedence.resolve_non_section_offset(start, items).unwrap();
|
fn opt_qn_equivalent(a: &Option<Tree>, b: &Option<Tree>) -> bool {
|
||||||
|
match (a, b) {
|
||||||
(qn, args, return_)
|
(Some(a), Some(b)) => qn_equivalent(a, b),
|
||||||
|
(None, None) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a sequence of argument definitions.
|
/// Parse a sequence of argument definitions.
|
||||||
|
@ -3,12 +3,16 @@ use crate::prelude::*;
|
|||||||
use crate::syntax::item;
|
use crate::syntax::item;
|
||||||
use crate::syntax::maybe_with_error;
|
use crate::syntax::maybe_with_error;
|
||||||
use crate::syntax::operator::Precedence;
|
use crate::syntax::operator::Precedence;
|
||||||
|
use crate::syntax::statement::compound_lines;
|
||||||
use crate::syntax::statement::function_def::parse_constructor_definition;
|
use crate::syntax::statement::function_def::parse_constructor_definition;
|
||||||
use crate::syntax::statement::function_def::parse_type_args;
|
use crate::syntax::statement::function_def::parse_type_args;
|
||||||
use crate::syntax::statement::parse_statement;
|
use crate::syntax::statement::parse_statement;
|
||||||
use crate::syntax::statement::scan_private_keywords;
|
use crate::syntax::statement::scan_private_keywords;
|
||||||
use crate::syntax::statement::EvaluationContext;
|
use crate::syntax::statement::EvaluationContext;
|
||||||
|
use crate::syntax::statement::Line;
|
||||||
use crate::syntax::statement::StatementContext;
|
use crate::syntax::statement::StatementContext;
|
||||||
|
use crate::syntax::statement::StatementOrPrefix;
|
||||||
|
use crate::syntax::statement::StatementPrefix;
|
||||||
use crate::syntax::statement::VisibilityContext;
|
use crate::syntax::statement::VisibilityContext;
|
||||||
use crate::syntax::token;
|
use crate::syntax::token;
|
||||||
use crate::syntax::tree;
|
use crate::syntax::tree;
|
||||||
@ -44,20 +48,17 @@ pub fn try_parse_type_def<'s>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let body = if let Some(Item::Block(lines)) = items.last_mut() {
|
let body = if let Some(Item::Block(lines)) = items.last_mut() {
|
||||||
let block = mem::take(lines).into_vec();
|
let mut block = mem::take(lines).into_vec();
|
||||||
items.pop();
|
items.pop();
|
||||||
let lines = block.into_iter().map(|item::Line { newline, mut items }| block::Line {
|
let lines = compound_lines(&mut block, |prefixes, mut line| {
|
||||||
newline,
|
if let Some(Item::Token(token)) = line.items.first_mut() {
|
||||||
expression: {
|
if matches!(token.variant, token::Variant::Operator(_)) {
|
||||||
if let Some(Item::Token(token)) = items.first_mut() {
|
let opr_ident =
|
||||||
if matches!(token.variant, token::Variant::Operator(_)) {
|
token::variant::Ident { is_operator_lexically: true, ..default() };
|
||||||
let opr_ident =
|
token.variant = token::Variant::Ident(opr_ident);
|
||||||
token::variant::Ident { is_operator_lexically: true, ..default() };
|
|
||||||
token.variant = token::Variant::Ident(opr_ident);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
parse_type_body_statement(items, precedence, args_buffer)
|
}
|
||||||
},
|
parse_type_body_statement(prefixes, line, precedence, args_buffer)
|
||||||
});
|
});
|
||||||
block::compound_lines(lines).collect()
|
block::compound_lines(lines).collect()
|
||||||
} else {
|
} else {
|
||||||
@ -77,46 +78,61 @@ pub fn try_parse_type_def<'s>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_type_body_statement<'s>(
|
fn parse_type_body_statement<'s>(
|
||||||
mut items: Vec<Item<'s>>,
|
prefixes: &mut Vec<Line<'s, StatementPrefix<'s>>>,
|
||||||
|
mut line: item::Line<'s>,
|
||||||
precedence: &mut Precedence<'s>,
|
precedence: &mut Precedence<'s>,
|
||||||
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
args_buffer: &mut Vec<ArgumentDefinition<'s>>,
|
||||||
) -> Option<Tree<'s>> {
|
) -> Line<'s, StatementOrPrefix<'s>> {
|
||||||
let private_keywords = scan_private_keywords(&items);
|
let private_keywords = scan_private_keywords(&line.items);
|
||||||
let statement = match items.get(private_keywords) {
|
match line.items.get(private_keywords) {
|
||||||
Some(Item::Token(Token { variant: token::Variant::Ident(ident), .. }))
|
Some(Item::Token(Token { variant: token::Variant::Ident(ident), .. }))
|
||||||
if ident.is_type
|
if ident.is_type
|
||||||
&& !items
|
&& !line
|
||||||
|
.items
|
||||||
.get(private_keywords + 1)
|
.get(private_keywords + 1)
|
||||||
.is_some_and(|item| Spacing::of_item(item) == Spacing::Unspaced) =>
|
.is_some_and(|item| Spacing::of_item(item) == Spacing::Unspaced) =>
|
||||||
Some(parse_constructor_definition(
|
{
|
||||||
|
let item::Line { newline, mut items } = line;
|
||||||
|
let def = parse_constructor_definition(
|
||||||
&mut items,
|
&mut items,
|
||||||
0,
|
0,
|
||||||
private_keywords,
|
private_keywords,
|
||||||
precedence,
|
precedence,
|
||||||
args_buffer,
|
args_buffer,
|
||||||
)),
|
);
|
||||||
None => None,
|
Line {
|
||||||
_ => {
|
newline,
|
||||||
let tree = parse_statement(&mut items, 0, precedence, args_buffer, StatementContext {
|
content: apply_excess_private_keywords(Some(def), items.drain(..))
|
||||||
evaluation_context: EvaluationContext::Lazy,
|
.map(StatementOrPrefix::from),
|
||||||
visibility_context: VisibilityContext::Public,
|
}
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let error = match &tree.variant {
|
|
||||||
tree::Variant::Function(_)
|
|
||||||
| tree::Variant::ForeignFunction(_)
|
|
||||||
| tree::Variant::Assignment(_)
|
|
||||||
| tree::Variant::Documented(_)
|
|
||||||
| tree::Variant::Annotated(_)
|
|
||||||
| tree::Variant::AnnotatedBuiltin(_) => None,
|
|
||||||
tree::Variant::TypeSignature(_) => None,
|
|
||||||
tree::Variant::TypeDef(_) => None,
|
|
||||||
_ => Some(SyntaxError::UnexpectedExpressionInTypeBody),
|
|
||||||
};
|
|
||||||
maybe_with_error(tree, error).into()
|
|
||||||
}
|
}
|
||||||
};
|
None => Line {
|
||||||
apply_excess_private_keywords(statement, items.drain(..))
|
newline: line.newline,
|
||||||
|
content: apply_excess_private_keywords(None, line.items.drain(..))
|
||||||
|
.map(StatementOrPrefix::from),
|
||||||
|
},
|
||||||
|
_ => parse_statement(prefixes, line, precedence, args_buffer, StatementContext {
|
||||||
|
evaluation_context: EvaluationContext::Lazy,
|
||||||
|
visibility_context: VisibilityContext::Public,
|
||||||
|
tail_expression: false,
|
||||||
|
})
|
||||||
|
.map_content(|statement_or_prefix| {
|
||||||
|
statement_or_prefix.map_statement(|tree| {
|
||||||
|
let error = match &tree.variant {
|
||||||
|
tree::Variant::Function(_)
|
||||||
|
| tree::Variant::ForeignFunction(_)
|
||||||
|
| tree::Variant::Assignment(_)
|
||||||
|
| tree::Variant::Documented(_)
|
||||||
|
| tree::Variant::Annotated(_)
|
||||||
|
| tree::Variant::AnnotatedBuiltin(_) => None,
|
||||||
|
tree::Variant::TypeSignatureDeclaration(_) => None,
|
||||||
|
tree::Variant::TypeDef(_) => None,
|
||||||
|
_ => Some(SyntaxError::UnexpectedExpressionInTypeBody),
|
||||||
|
};
|
||||||
|
maybe_with_error(tree, error)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_excess_private_keywords<'s>(
|
fn apply_excess_private_keywords<'s>(
|
||||||
|
@ -215,6 +215,8 @@ macro_rules! with_ast_definition { ($f:ident ($($args:tt)*)) => { $f! { $($args)
|
|||||||
},
|
},
|
||||||
/// A function definition, like `add x y = x + y`.
|
/// A function definition, like `add x y = x + y`.
|
||||||
Function {
|
Function {
|
||||||
|
/// A type signature for the function, on its own line.
|
||||||
|
pub signature_line: Option<TypeSignatureLine<'s>>,
|
||||||
/// The `private` keyword, if present. This is allowed at top level and in type
|
/// The `private` keyword, if present. This is allowed at top level and in type
|
||||||
/// definitions, must be `None` if the context is a function body.
|
/// definitions, must be `None` if the context is a function body.
|
||||||
pub private: Option<token::PrivateKeyword<'s>>,
|
pub private: Option<token::PrivateKeyword<'s>>,
|
||||||
@ -268,15 +270,10 @@ macro_rules! with_ast_definition { ($f:ident ($($args:tt)*)) => { $f! { $($args)
|
|||||||
pub body: Option<Tree<'s>>,
|
pub body: Option<Tree<'s>>,
|
||||||
pub close: Option<token::CloseSymbol<'s>>,
|
pub close: Option<token::CloseSymbol<'s>>,
|
||||||
},
|
},
|
||||||
/// Statement declaring the type of a variable.
|
/// Declaration of the type of a function, that was not able to be attached to a subsequent
|
||||||
TypeSignature {
|
/// function definition.
|
||||||
/// (Qualified) name of the item whose type is being declared.
|
TypeSignatureDeclaration {
|
||||||
pub variable: Tree<'s>,
|
pub signature: TypeSignature<'s>,
|
||||||
/// The `:` token.
|
|
||||||
pub operator: token::TypeAnnotationOperator<'s>,
|
|
||||||
/// The variable's type.
|
|
||||||
#[reflect(rename = "type")]
|
|
||||||
pub type_: Tree<'s>,
|
|
||||||
},
|
},
|
||||||
/// An expression with explicit type information attached.
|
/// An expression with explicit type information attached.
|
||||||
TypeAnnotated {
|
TypeAnnotated {
|
||||||
@ -532,6 +529,41 @@ impl<'s> span::Builder<'s> for FractionalDigits<'s> {
|
|||||||
|
|
||||||
// === Functions ===
|
// === Functions ===
|
||||||
|
|
||||||
|
/// A function type signature line.
|
||||||
|
#[cfg_attr(feature = "debug", derive(Visitor))]
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)]
|
||||||
|
pub struct TypeSignatureLine<'s> {
|
||||||
|
/// The type signature.
|
||||||
|
pub signature: TypeSignature<'s>,
|
||||||
|
/// The end of the type signature line.
|
||||||
|
pub newlines: NonEmptyVec<token::Newline<'s>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> span::Builder<'s> for TypeSignatureLine<'s> {
|
||||||
|
fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> {
|
||||||
|
span.add(&mut self.signature).add(&mut self.newlines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specification of the type of an item.
|
||||||
|
#[cfg_attr(feature = "debug", derive(Visitor))]
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)]
|
||||||
|
pub struct TypeSignature<'s> {
|
||||||
|
/// (Qualified) name of the item whose type is being declared.
|
||||||
|
pub name: Tree<'s>,
|
||||||
|
/// The `:` token.
|
||||||
|
pub operator: token::TypeAnnotationOperator<'s>,
|
||||||
|
/// The declared type.
|
||||||
|
#[reflect(rename = "type")]
|
||||||
|
pub type_: Tree<'s>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> span::Builder<'s> for TypeSignature<'s> {
|
||||||
|
fn add_to_span(&mut self, span: Span<'s>) -> Span<'s> {
|
||||||
|
span.add(&mut self.name).add(&mut self.operator).add(&mut self.type_)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A function argument definition.
|
/// A function argument definition.
|
||||||
#[cfg_attr(feature = "debug", derive(Visitor))]
|
#[cfg_attr(feature = "debug", derive(Visitor))]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Reflect, Deserialize)]
|
||||||
|
@ -50,7 +50,7 @@ impl<'s> span::Builder<'s> for Line<'s> {
|
|||||||
|
|
||||||
/// Parse the top-level of a module.
|
/// Parse the top-level of a module.
|
||||||
pub fn parse_module<'s>(
|
pub fn parse_module<'s>(
|
||||||
lines: impl IntoIterator<Item = item::Line<'s>>,
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
precedence: &mut operator::Precedence<'s>,
|
precedence: &mut operator::Precedence<'s>,
|
||||||
) -> Tree<'s> {
|
) -> Tree<'s> {
|
||||||
BodyBlockParser::default().parse_module(lines, precedence)
|
BodyBlockParser::default().parse_module(lines, precedence)
|
||||||
@ -58,7 +58,7 @@ pub fn parse_module<'s>(
|
|||||||
|
|
||||||
/// Parse a body block.
|
/// Parse a body block.
|
||||||
pub fn parse_block<'s>(
|
pub fn parse_block<'s>(
|
||||||
lines: impl IntoIterator<Item = item::Line<'s>>,
|
lines: &mut Vec<item::Line<'s>>,
|
||||||
precedence: &mut operator::Precedence<'s>,
|
precedence: &mut operator::Precedence<'s>,
|
||||||
) -> Tree<'s> {
|
) -> Tree<'s> {
|
||||||
BodyBlockParser::default().parse_body_block(lines, precedence)
|
BodyBlockParser::default().parse_body_block(lines, precedence)
|
||||||
|
@ -50,7 +50,7 @@ where Inner: ItemConsumer<'s> + Finish
|
|||||||
};
|
};
|
||||||
items.push(Item::Tree(match block_context {
|
items.push(Item::Tree(match block_context {
|
||||||
BlockContext::Body =>
|
BlockContext::Body =>
|
||||||
self.block_parser.parse_body_block(lines.into_vec(), &mut child),
|
self.block_parser.parse_body_block(&mut lines.into_vec(), &mut child),
|
||||||
BlockContext::ArgumentOrOperator => {
|
BlockContext::ArgumentOrOperator => {
|
||||||
for item::Line { newline, items } in lines.into_vec() {
|
for item::Line { newline, items } in lines.into_vec() {
|
||||||
self.block_builder.push(newline, items, &mut child);
|
self.block_builder.push(newline, items, &mut child);
|
||||||
|
Loading…
Reference in New Issue
Block a user