mirror of https://github.com/Wilfred/difftastic/
Merge commit '09dbf221d7491dc8d8839616b27c21b9c025c457'
commit
1dd7bbebe8
@ -0,0 +1,22 @@
|
||||
name: Fuzz Parser
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- src/scanner.c
|
||||
pull_request:
|
||||
paths:
|
||||
- src/scanner.c
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Parser fuzzing
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: vigoux/tree-sitter-fuzz-action@v1
|
||||
with:
|
||||
language: elm
|
||||
external-scanner: src/scanner.c
|
||||
time: 60
|
||||
@ -0,0 +1,44 @@
|
||||
name: Validate that changes doesn't break elm-language-server
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node-version: [18, 20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: "tree-sitter-elm"
|
||||
- uses: actions/checkout@v4
|
||||
name: Checkout main branch of elm-language-server
|
||||
with:
|
||||
repository: "elm-tooling/elm-language-server"
|
||||
path: "elm-language-server"
|
||||
- name: Install tree-sitter dependencies and generate wasm bundle
|
||||
run: |
|
||||
cd tree-sitter-elm/
|
||||
npm i
|
||||
npm run build
|
||||
npx tree-sitter build-wasm
|
||||
mv ./tree-sitter-elm.wasm ../elm-language-server/tree-sitter-elm.wasm -f
|
||||
|
||||
- name: Install elm-language-server dependencies, compile, and run tests
|
||||
run: |
|
||||
cd elm-language-server/
|
||||
npm i
|
||||
npm run compile
|
||||
npm install -g elm-format
|
||||
npm test
|
||||
@ -0,0 +1,43 @@
|
||||
// swift-tools-version:5.3
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TreeSitterElm",
|
||||
platforms: [.macOS(.v10_13), .iOS(.v11)],
|
||||
products: [
|
||||
.library(name: "TreeSitterElm", targets: ["TreeSitterElm"]),
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(name: "TreeSitterElm",
|
||||
path: ".",
|
||||
exclude: [
|
||||
"binding.gyp",
|
||||
"bindings",
|
||||
"Cargo.toml",
|
||||
"docs",
|
||||
"examples",
|
||||
"grammar.js",
|
||||
"HOW_TO_RELEASE.md",
|
||||
"index.d.ts",
|
||||
"LICENSE.md",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"script",
|
||||
"src/grammar.json",
|
||||
"src/node-types.json",
|
||||
"test",
|
||||
"tsconfig.json",
|
||||
],
|
||||
sources: [
|
||||
"src/parser.c",
|
||||
"src/scanner.c",
|
||||
],
|
||||
resources: [
|
||||
.copy("queries")
|
||||
],
|
||||
publicHeadersPath: "bindings/swift",
|
||||
cSettings: [.headerSearchPath("src")])
|
||||
]
|
||||
)
|
||||
@ -0,0 +1,16 @@
|
||||
#ifndef TREE_SITTER_ELM_H_
|
||||
#define TREE_SITTER_ELM_H_
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern TSLanguage *tree_sitter_elm();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ELM_H_
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1,882 +0,0 @@
|
||||
export interface Parser {
|
||||
parse(input: string | Input, previousTree?: Tree, options?: {bufferSize?: number, includedRanges?: Range[]}): Tree;
|
||||
getLanguage(): any;
|
||||
setLanguage(language: any): void;
|
||||
getLogger(): Logger;
|
||||
setLogger(logFunc: Logger): void;
|
||||
}
|
||||
|
||||
export type Point = {
|
||||
row: number;
|
||||
column: number;
|
||||
};
|
||||
|
||||
export type Range = {
|
||||
startIndex: number,
|
||||
endIndex: number,
|
||||
startPosition: Point,
|
||||
endPosition: Point
|
||||
};
|
||||
|
||||
export type Edit = {
|
||||
startIndex: number;
|
||||
oldEndIndex: number;
|
||||
newEndIndex: number;
|
||||
startPosition: Point;
|
||||
oldEndPosition: Point;
|
||||
newEndPosition: Point;
|
||||
};
|
||||
|
||||
export type Logger = (
|
||||
message: string,
|
||||
params: {[param: string]: string},
|
||||
type: "parse" | "lex"
|
||||
) => void;
|
||||
|
||||
export interface Input {
|
||||
seek(index: number): void;
|
||||
read(): any;
|
||||
}
|
||||
|
||||
interface SyntaxNodeBase {
|
||||
tree: Tree;
|
||||
type: string;
|
||||
isNamed: boolean;
|
||||
text: string;
|
||||
startPosition: Point;
|
||||
endPosition: Point;
|
||||
startIndex: number;
|
||||
endIndex: number;
|
||||
parent: SyntaxNode | null;
|
||||
children: Array<SyntaxNode>;
|
||||
namedChildren: Array<SyntaxNode>;
|
||||
childCount: number;
|
||||
namedChildCount: number;
|
||||
firstChild: SyntaxNode | null;
|
||||
firstNamedChild: SyntaxNode | null;
|
||||
lastChild: SyntaxNode | null;
|
||||
lastNamedChild: SyntaxNode | null;
|
||||
nextSibling: SyntaxNode | null;
|
||||
nextNamedSibling: SyntaxNode | null;
|
||||
previousSibling: SyntaxNode | null;
|
||||
previousNamedSibling: SyntaxNode | null;
|
||||
|
||||
hasChanges(): boolean;
|
||||
hasError(): boolean;
|
||||
isMissing(): boolean;
|
||||
toString(): string;
|
||||
child(index: number): SyntaxNode | null;
|
||||
namedChild(index: number): SyntaxNode | null;
|
||||
firstChildForIndex(index: number): SyntaxNode | null;
|
||||
firstNamedChildForIndex(index: number): SyntaxNode | null;
|
||||
|
||||
descendantForIndex(index: number): SyntaxNode;
|
||||
descendantForIndex(startIndex: number, endIndex: number): SyntaxNode;
|
||||
namedDescendantForIndex(index: number): SyntaxNode;
|
||||
namedDescendantForIndex(startIndex: number, endIndex: number): SyntaxNode;
|
||||
descendantForPosition(position: Point): SyntaxNode;
|
||||
descendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode;
|
||||
namedDescendantForPosition(position: Point): SyntaxNode;
|
||||
namedDescendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode;
|
||||
descendantsOfType<T extends TypeString>(types: T | readonly T[], startPosition?: Point, endPosition?: Point): NodeOfType<T>[];
|
||||
|
||||
closest<T extends SyntaxType>(types: T | readonly T[]): NamedNode<T> | null;
|
||||
walk(): TreeCursor;
|
||||
}
|
||||
|
||||
export interface TreeCursor {
|
||||
nodeType: string;
|
||||
nodeText: string;
|
||||
nodeIsNamed: boolean;
|
||||
startPosition: Point;
|
||||
endPosition: Point;
|
||||
startIndex: number;
|
||||
endIndex: number;
|
||||
readonly currentNode: SyntaxNode
|
||||
|
||||
reset(node: SyntaxNode): void
|
||||
gotoParent(): boolean;
|
||||
gotoFirstChild(): boolean;
|
||||
gotoFirstChildForIndex(index: number): boolean;
|
||||
gotoNextSibling(): boolean;
|
||||
}
|
||||
|
||||
export interface Tree {
|
||||
readonly rootNode: SyntaxNode;
|
||||
|
||||
edit(delta: Edit): Tree;
|
||||
walk(): TreeCursor;
|
||||
getChangedRanges(other: Tree): Range[];
|
||||
getEditedRange(other: Tree): Range;
|
||||
}
|
||||
|
||||
interface NamedNodeBase extends SyntaxNodeBase {
|
||||
isNamed: true;
|
||||
}
|
||||
|
||||
/** An unnamed node with the given type string. */
|
||||
export interface UnnamedNode<T extends string = string> extends SyntaxNodeBase {
|
||||
type: T;
|
||||
isNamed: false;
|
||||
}
|
||||
|
||||
type PickNamedType<Node, T extends string> = Node extends { type: T; isNamed: true } ? Node : never;
|
||||
|
||||
type PickType<Node, T extends string> = Node extends { type: T } ? Node : never;
|
||||
|
||||
/** A named node with the given `type` string. */
|
||||
export type NamedNode<T extends SyntaxType = SyntaxType> = PickNamedType<SyntaxNode, T>;
|
||||
|
||||
/**
|
||||
* A node with the given `type` string.
|
||||
*
|
||||
* Note that this matches both named and unnamed nodes. Use `NamedNode<T>` to pick only named nodes.
|
||||
*/
|
||||
export type NodeOfType<T extends string> = PickType<SyntaxNode, T>;
|
||||
|
||||
interface TreeCursorOfType<S extends string, T extends SyntaxNodeBase> {
|
||||
nodeType: S;
|
||||
currentNode: T;
|
||||
}
|
||||
|
||||
type TreeCursorRecord = { [K in TypeString]: TreeCursorOfType<K, NodeOfType<K>> };
|
||||
|
||||
/**
|
||||
* A tree cursor whose `nodeType` correlates with `currentNode`.
|
||||
*
|
||||
* The typing becomes invalid once the underlying cursor is mutated.
|
||||
*
|
||||
* The intention is to cast a `TreeCursor` to `TypedTreeCursor` before
|
||||
* switching on `nodeType`.
|
||||
*
|
||||
* For example:
|
||||
* ```ts
|
||||
* let cursor = root.walk();
|
||||
* while (cursor.gotoNextSibling()) {
|
||||
* const c = cursor as TypedTreeCursor;
|
||||
* switch (c.nodeType) {
|
||||
* case SyntaxType.Foo: {
|
||||
* let node = c.currentNode; // Typed as FooNode.
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export type TypedTreeCursor = TreeCursorRecord[keyof TreeCursorRecord];
|
||||
|
||||
export interface ErrorNode extends NamedNodeBase {
|
||||
type: SyntaxType.ERROR;
|
||||
hasError(): true;
|
||||
}
|
||||
|
||||
export const enum SyntaxType {
|
||||
ERROR = "ERROR",
|
||||
AnonymousFunctionExpr = "anonymous_function_expr",
|
||||
AnythingPattern = "anything_pattern",
|
||||
AsClause = "as_clause",
|
||||
BinOpExpr = "bin_op_expr",
|
||||
BlockComment = "block_comment",
|
||||
CaseOfBranch = "case_of_branch",
|
||||
CaseOfExpr = "case_of_expr",
|
||||
CharConstantExpr = "char_constant_expr",
|
||||
ConsPattern = "cons_pattern",
|
||||
ExposedOperator = "exposed_operator",
|
||||
ExposedType = "exposed_type",
|
||||
ExposedUnionConstructors = "exposed_union_constructors",
|
||||
ExposedValue = "exposed_value",
|
||||
ExposingList = "exposing_list",
|
||||
Field = "field",
|
||||
FieldAccessExpr = "field_access_expr",
|
||||
FieldAccessorFunctionExpr = "field_accessor_function_expr",
|
||||
FieldType = "field_type",
|
||||
File = "file",
|
||||
FunctionCallExpr = "function_call_expr",
|
||||
FunctionDeclarationLeft = "function_declaration_left",
|
||||
GlslCodeExpr = "glsl_code_expr",
|
||||
IfElseExpr = "if_else_expr",
|
||||
ImportClause = "import_clause",
|
||||
InfixDeclaration = "infix_declaration",
|
||||
LetInExpr = "let_in_expr",
|
||||
ListExpr = "list_expr",
|
||||
ListPattern = "list_pattern",
|
||||
LowerPattern = "lower_pattern",
|
||||
LowerTypeName = "lower_type_name",
|
||||
ModuleDeclaration = "module_declaration",
|
||||
NegateExpr = "negate_expr",
|
||||
NullaryConstructorArgumentPattern = "nullary_constructor_argument_pattern",
|
||||
NumberConstantExpr = "number_constant_expr",
|
||||
Operator = "operator",
|
||||
OperatorAsFunctionExpr = "operator_as_function_expr",
|
||||
OperatorIdentifier = "operator_identifier",
|
||||
ParenthesizedExpr = "parenthesized_expr",
|
||||
Pattern = "pattern",
|
||||
PortAnnotation = "port_annotation",
|
||||
RecordBaseIdentifier = "record_base_identifier",
|
||||
RecordExpr = "record_expr",
|
||||
RecordPattern = "record_pattern",
|
||||
RecordType = "record_type",
|
||||
StringConstantExpr = "string_constant_expr",
|
||||
TupleExpr = "tuple_expr",
|
||||
TuplePattern = "tuple_pattern",
|
||||
TupleType = "tuple_type",
|
||||
TypeAliasDeclaration = "type_alias_declaration",
|
||||
TypeAnnotation = "type_annotation",
|
||||
TypeDeclaration = "type_declaration",
|
||||
TypeExpression = "type_expression",
|
||||
TypeRef = "type_ref",
|
||||
TypeVariable = "type_variable",
|
||||
UnionPattern = "union_pattern",
|
||||
UnionVariant = "union_variant",
|
||||
UnitExpr = "unit_expr",
|
||||
UpperCaseQid = "upper_case_qid",
|
||||
ValueDeclaration = "value_declaration",
|
||||
ValueExpr = "value_expr",
|
||||
ValueQid = "value_qid",
|
||||
Alias = "alias",
|
||||
Arrow = "arrow",
|
||||
As = "as",
|
||||
Backslash = "backslash",
|
||||
Case = "case",
|
||||
CloseChar = "close_char",
|
||||
CloseQuote = "close_quote",
|
||||
Colon = "colon",
|
||||
Dot = "dot",
|
||||
DoubleDot = "double_dot",
|
||||
Effect = "effect",
|
||||
Eq = "eq",
|
||||
Exposing = "exposing",
|
||||
GlslContent = "glsl_content",
|
||||
Import = "import",
|
||||
Infix = "infix",
|
||||
InvalidStringEscape = "invalid_string_escape",
|
||||
LineComment = "line_comment",
|
||||
LowerCaseIdentifier = "lower_case_identifier",
|
||||
Module = "module",
|
||||
NumberLiteral = "number_literal",
|
||||
Of = "of",
|
||||
OpenChar = "open_char",
|
||||
OpenQuote = "open_quote",
|
||||
Port = "port",
|
||||
RegularStringPart = "regular_string_part",
|
||||
StringEscape = "string_escape",
|
||||
Type = "type",
|
||||
Underscore = "underscore",
|
||||
UpperCaseIdentifier = "upper_case_identifier",
|
||||
Where = "where",
|
||||
}
|
||||
|
||||
export type UnnamedType =
|
||||
| "&&"
|
||||
| "("
|
||||
| ")"
|
||||
| "*"
|
||||
| "+"
|
||||
| "++"
|
||||
| ","
|
||||
| "-"
|
||||
| "-}"
|
||||
| "/"
|
||||
| "//"
|
||||
| "/="
|
||||
| "::"
|
||||
| "<"
|
||||
| "</>"
|
||||
| "<<"
|
||||
| "<="
|
||||
| "<?>"
|
||||
| "<|"
|
||||
| "=="
|
||||
| ">"
|
||||
| ">="
|
||||
| ">>"
|
||||
| "["
|
||||
| "]"
|
||||
| "^"
|
||||
| "else"
|
||||
| "if"
|
||||
| "in"
|
||||
| "let"
|
||||
| "then"
|
||||
| "{"
|
||||
| "{-"
|
||||
| "|"
|
||||
| "|."
|
||||
| "|="
|
||||
| "|>"
|
||||
| "||"
|
||||
| "}"
|
||||
;
|
||||
|
||||
export type TypeString = SyntaxType | UnnamedType;
|
||||
|
||||
export type SyntaxNode =
|
||||
| AnonymousFunctionExprNode
|
||||
| AnythingPatternNode
|
||||
| AsClauseNode
|
||||
| BinOpExprNode
|
||||
| BlockCommentNode
|
||||
| CaseOfBranchNode
|
||||
| CaseOfExprNode
|
||||
| CharConstantExprNode
|
||||
| ConsPatternNode
|
||||
| ExposedOperatorNode
|
||||
| ExposedTypeNode
|
||||
| ExposedUnionConstructorsNode
|
||||
| ExposedValueNode
|
||||
| ExposingListNode
|
||||
| FieldNode
|
||||
| FieldAccessExprNode
|
||||
| FieldAccessorFunctionExprNode
|
||||
| FieldTypeNode
|
||||
| FileNode
|
||||
| FunctionCallExprNode
|
||||
| FunctionDeclarationLeftNode
|
||||
| GlslCodeExprNode
|
||||
| IfElseExprNode
|
||||
| ImportClauseNode
|
||||
| InfixDeclarationNode
|
||||
| LetInExprNode
|
||||
| ListExprNode
|
||||
| ListPatternNode
|
||||
| LowerPatternNode
|
||||
| LowerTypeNameNode
|
||||
| ModuleDeclarationNode
|
||||
| NegateExprNode
|
||||
| NullaryConstructorArgumentPatternNode
|
||||
| NumberConstantExprNode
|
||||
| OperatorNode
|
||||
| OperatorAsFunctionExprNode
|
||||
| OperatorIdentifierNode
|
||||
| ParenthesizedExprNode
|
||||
| PatternNode
|
||||
| PortAnnotationNode
|
||||
| RecordBaseIdentifierNode
|
||||
| RecordExprNode
|
||||
| RecordPatternNode
|
||||
| RecordTypeNode
|
||||
| StringConstantExprNode
|
||||
| TupleExprNode
|
||||
| TuplePatternNode
|
||||
| TupleTypeNode
|
||||
| TypeAliasDeclarationNode
|
||||
| TypeAnnotationNode
|
||||
| TypeDeclarationNode
|
||||
| TypeExpressionNode
|
||||
| TypeRefNode
|
||||
| TypeVariableNode
|
||||
| UnionPatternNode
|
||||
| UnionVariantNode
|
||||
| UnitExprNode
|
||||
| UpperCaseQidNode
|
||||
| ValueDeclarationNode
|
||||
| ValueExprNode
|
||||
| ValueQidNode
|
||||
| UnnamedNode<"&&">
|
||||
| UnnamedNode<"(">
|
||||
| UnnamedNode<")">
|
||||
| UnnamedNode<"*">
|
||||
| UnnamedNode<"+">
|
||||
| UnnamedNode<"++">
|
||||
| UnnamedNode<",">
|
||||
| UnnamedNode<"-">
|
||||
| UnnamedNode<"-}">
|
||||
| UnnamedNode<"/">
|
||||
| UnnamedNode<"//">
|
||||
| UnnamedNode<"/=">
|
||||
| UnnamedNode<"::">
|
||||
| UnnamedNode<"<">
|
||||
| UnnamedNode<"</>">
|
||||
| UnnamedNode<"<<">
|
||||
| UnnamedNode<"<=">
|
||||
| UnnamedNode<"<?>">
|
||||
| UnnamedNode<"<|">
|
||||
| UnnamedNode<"==">
|
||||
| UnnamedNode<">">
|
||||
| UnnamedNode<">=">
|
||||
| UnnamedNode<">>">
|
||||
| UnnamedNode<"[">
|
||||
| UnnamedNode<"]">
|
||||
| UnnamedNode<"^">
|
||||
| AliasNode
|
||||
| ArrowNode
|
||||
| AsNode
|
||||
| BackslashNode
|
||||
| CaseNode
|
||||
| CloseCharNode
|
||||
| CloseQuoteNode
|
||||
| ColonNode
|
||||
| DotNode
|
||||
| DoubleDotNode
|
||||
| EffectNode
|
||||
| UnnamedNode<"else">
|
||||
| EqNode
|
||||
| ExposingNode
|
||||
| GlslContentNode
|
||||
| UnnamedNode<"if">
|
||||
| ImportNode
|
||||
| UnnamedNode<"in">
|
||||
| InfixNode
|
||||
| InvalidStringEscapeNode
|
||||
| UnnamedNode<"let">
|
||||
| LineCommentNode
|
||||
| LowerCaseIdentifierNode
|
||||
| ModuleNode
|
||||
| NumberLiteralNode
|
||||
| OfNode
|
||||
| OpenCharNode
|
||||
| OpenQuoteNode
|
||||
| PortNode
|
||||
| RegularStringPartNode
|
||||
| StringEscapeNode
|
||||
| UnnamedNode<"then">
|
||||
| TypeNode
|
||||
| UnderscoreNode
|
||||
| UpperCaseIdentifierNode
|
||||
| WhereNode
|
||||
| UnnamedNode<"{">
|
||||
| UnnamedNode<"{-">
|
||||
| UnnamedNode<"|">
|
||||
| UnnamedNode<"|.">
|
||||
| UnnamedNode<"|=">
|
||||
| UnnamedNode<"|>">
|
||||
| UnnamedNode<"||">
|
||||
| UnnamedNode<"}">
|
||||
| ErrorNode
|
||||
;
|
||||
|
||||
export interface AnonymousFunctionExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.AnonymousFunctionExpr;
|
||||
exprNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
paramNodes: PatternNode[];
|
||||
}
|
||||
|
||||
export interface AnythingPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.AnythingPattern;
|
||||
}
|
||||
|
||||
export interface AsClauseNode extends NamedNodeBase {
|
||||
type: SyntaxType.AsClause;
|
||||
nameNode: UpperCaseIdentifierNode;
|
||||
}
|
||||
|
||||
export interface BinOpExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.BinOpExpr;
|
||||
partNodes: (AnonymousFunctionExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode)[];
|
||||
}
|
||||
|
||||
export interface BlockCommentNode extends NamedNodeBase {
|
||||
type: SyntaxType.BlockComment;
|
||||
}
|
||||
|
||||
export interface CaseOfBranchNode extends NamedNodeBase {
|
||||
type: SyntaxType.CaseOfBranch;
|
||||
exprNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
patternNode: PatternNode;
|
||||
}
|
||||
|
||||
export interface CaseOfExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.CaseOfExpr;
|
||||
branchNodes: CaseOfBranchNode[];
|
||||
exprNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
}
|
||||
|
||||
export interface CharConstantExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.CharConstantExpr;
|
||||
}
|
||||
|
||||
export interface ConsPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.ConsPattern;
|
||||
partNodes: (UnnamedNode<"("> | UnnamedNode<")"> | AnythingPatternNode | CharConstantExprNode | ConsPatternNode | ListPatternNode | LowerPatternNode | NumberConstantExprNode | PatternNode | RecordPatternNode | StringConstantExprNode | TuplePatternNode | UnionPatternNode | UnitExprNode)[];
|
||||
}
|
||||
|
||||
export interface ExposedOperatorNode extends NamedNodeBase {
|
||||
type: SyntaxType.ExposedOperator;
|
||||
operatorNode: OperatorIdentifierNode;
|
||||
}
|
||||
|
||||
export interface ExposedTypeNode extends NamedNodeBase {
|
||||
type: SyntaxType.ExposedType;
|
||||
}
|
||||
|
||||
export interface ExposedUnionConstructorsNode extends NamedNodeBase {
|
||||
type: SyntaxType.ExposedUnionConstructors;
|
||||
}
|
||||
|
||||
export interface ExposedValueNode extends NamedNodeBase {
|
||||
type: SyntaxType.ExposedValue;
|
||||
}
|
||||
|
||||
export interface ExposingListNode extends NamedNodeBase {
|
||||
type: SyntaxType.ExposingList;
|
||||
doubleDotNode?: DoubleDotNode;
|
||||
}
|
||||
|
||||
export interface FieldNode extends NamedNodeBase {
|
||||
type: SyntaxType.Field;
|
||||
expressionNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
nameNode: LowerCaseIdentifierNode;
|
||||
}
|
||||
|
||||
export interface FieldAccessExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.FieldAccessExpr;
|
||||
targetNode: FieldAccessExprNode | ParenthesizedExprNode | RecordExprNode | ValueExprNode;
|
||||
}
|
||||
|
||||
export interface FieldAccessorFunctionExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.FieldAccessorFunctionExpr;
|
||||
}
|
||||
|
||||
export interface FieldTypeNode extends NamedNodeBase {
|
||||
type: SyntaxType.FieldType;
|
||||
nameNode: LowerCaseIdentifierNode;
|
||||
typeExpressionNode: TypeExpressionNode;
|
||||
}
|
||||
|
||||
export interface FileNode extends NamedNodeBase {
|
||||
type: SyntaxType.File;
|
||||
moduleDeclarationNode?: ModuleDeclarationNode;
|
||||
}
|
||||
|
||||
export interface FunctionCallExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.FunctionCallExpr;
|
||||
argNodes: (AnonymousFunctionExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode)[];
|
||||
targetNode: FieldAccessExprNode | FieldAccessorFunctionExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | ValueExprNode;
|
||||
}
|
||||
|
||||
export interface FunctionDeclarationLeftNode extends NamedNodeBase {
|
||||
type: SyntaxType.FunctionDeclarationLeft;
|
||||
patternNodes: (UnnamedNode<"("> | UnnamedNode<")"> | AnythingPatternNode | CharConstantExprNode | ListPatternNode | LowerPatternNode | NumberConstantExprNode | PatternNode | RecordPatternNode | StringConstantExprNode | TuplePatternNode | UnitExprNode)[];
|
||||
}
|
||||
|
||||
export interface GlslCodeExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.GlslCodeExpr;
|
||||
contentNode: GlslContentNode;
|
||||
}
|
||||
|
||||
export interface IfElseExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.IfElseExpr;
|
||||
exprListNodes: (AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode)[];
|
||||
}
|
||||
|
||||
export interface ImportClauseNode extends NamedNodeBase {
|
||||
type: SyntaxType.ImportClause;
|
||||
asClauseNode?: AsClauseNode;
|
||||
exposingNode?: ExposingListNode;
|
||||
moduleNameNode: UpperCaseQidNode;
|
||||
}
|
||||
|
||||
export interface InfixDeclarationNode extends NamedNodeBase {
|
||||
type: SyntaxType.InfixDeclaration;
|
||||
associativityNode: LowerCaseIdentifierNode;
|
||||
operatorNode: OperatorIdentifierNode;
|
||||
precedenceNode: NumberLiteralNode;
|
||||
}
|
||||
|
||||
export interface LetInExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.LetInExpr;
|
||||
bodyNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
valueDeclarationNodes: ValueDeclarationNode[];
|
||||
}
|
||||
|
||||
export interface ListExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.ListExpr;
|
||||
exprListNodes: (AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode)[];
|
||||
}
|
||||
|
||||
export interface ListPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.ListPattern;
|
||||
partNodes: PatternNode[];
|
||||
}
|
||||
|
||||
export interface LowerPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.LowerPattern;
|
||||
}
|
||||
|
||||
export interface LowerTypeNameNode extends NamedNodeBase {
|
||||
type: SyntaxType.LowerTypeName;
|
||||
}
|
||||
|
||||
export interface ModuleDeclarationNode extends NamedNodeBase {
|
||||
type: SyntaxType.ModuleDeclaration;
|
||||
exposingNode: ExposingListNode;
|
||||
nameNode: UpperCaseQidNode;
|
||||
}
|
||||
|
||||
export interface NegateExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.NegateExpr;
|
||||
}
|
||||
|
||||
export interface NullaryConstructorArgumentPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.NullaryConstructorArgumentPattern;
|
||||
}
|
||||
|
||||
export interface NumberConstantExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.NumberConstantExpr;
|
||||
}
|
||||
|
||||
export interface OperatorNode extends NamedNodeBase {
|
||||
type: SyntaxType.Operator;
|
||||
}
|
||||
|
||||
export interface OperatorAsFunctionExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.OperatorAsFunctionExpr;
|
||||
operatorNode: OperatorIdentifierNode;
|
||||
}
|
||||
|
||||
export interface OperatorIdentifierNode extends NamedNodeBase {
|
||||
type: SyntaxType.OperatorIdentifier;
|
||||
}
|
||||
|
||||
export interface ParenthesizedExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.ParenthesizedExpr;
|
||||
expressionNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
}
|
||||
|
||||
export interface PatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.Pattern;
|
||||
childNode: AnythingPatternNode | CharConstantExprNode | ConsPatternNode | ListPatternNode | LowerPatternNode | NumberConstantExprNode | PatternNode | RecordPatternNode | StringConstantExprNode | TuplePatternNode | UnionPatternNode | UnitExprNode;
|
||||
patternAsNode?: LowerPatternNode;
|
||||
}
|
||||
|
||||
export interface PortAnnotationNode extends NamedNodeBase {
|
||||
type: SyntaxType.PortAnnotation;
|
||||
nameNode: LowerCaseIdentifierNode;
|
||||
typeExpressionNode: TypeExpressionNode;
|
||||
}
|
||||
|
||||
export interface RecordBaseIdentifierNode extends NamedNodeBase {
|
||||
type: SyntaxType.RecordBaseIdentifier;
|
||||
}
|
||||
|
||||
export interface RecordExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.RecordExpr;
|
||||
baseRecordNode?: RecordBaseIdentifierNode;
|
||||
fieldNodes: FieldNode[];
|
||||
}
|
||||
|
||||
export interface RecordPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.RecordPattern;
|
||||
patternListNodes: LowerPatternNode[];
|
||||
}
|
||||
|
||||
export interface RecordTypeNode extends NamedNodeBase {
|
||||
type: SyntaxType.RecordType;
|
||||
baseRecordNode?: RecordBaseIdentifierNode;
|
||||
fieldTypeNodes: FieldTypeNode[];
|
||||
}
|
||||
|
||||
export interface StringConstantExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.StringConstantExpr;
|
||||
}
|
||||
|
||||
export interface TupleExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.TupleExpr;
|
||||
exprNodes: (AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode)[];
|
||||
}
|
||||
|
||||
export interface TuplePatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.TuplePattern;
|
||||
patternNodes: PatternNode[];
|
||||
}
|
||||
|
||||
export interface TupleTypeNode extends NamedNodeBase {
|
||||
type: SyntaxType.TupleType;
|
||||
typeExpressionNodes: TypeExpressionNode[];
|
||||
unitExprNode?: UnitExprNode;
|
||||
}
|
||||
|
||||
export interface TypeAliasDeclarationNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeAliasDeclaration;
|
||||
nameNode: UpperCaseIdentifierNode;
|
||||
typeExpressionNode: TypeExpressionNode;
|
||||
typeVariableNodes: LowerTypeNameNode[];
|
||||
}
|
||||
|
||||
export interface TypeAnnotationNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeAnnotation;
|
||||
nameNode: LowerCaseIdentifierNode;
|
||||
typeExpressionNode: TypeExpressionNode;
|
||||
}
|
||||
|
||||
export interface TypeDeclarationNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeDeclaration;
|
||||
nameNode: UpperCaseIdentifierNode;
|
||||
typeNameNodes: LowerTypeNameNode[];
|
||||
unionVariantNodes: UnionVariantNode[];
|
||||
}
|
||||
|
||||
export interface TypeExpressionNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeExpression;
|
||||
partNodes: (RecordTypeNode | TupleTypeNode | TypeExpressionNode | TypeRefNode | TypeVariableNode)[];
|
||||
}
|
||||
|
||||
export interface TypeRefNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeRef;
|
||||
partNodes: (RecordTypeNode | TupleTypeNode | TypeExpressionNode | TypeRefNode | TypeVariableNode)[];
|
||||
}
|
||||
|
||||
export interface TypeVariableNode extends NamedNodeBase {
|
||||
type: SyntaxType.TypeVariable;
|
||||
}
|
||||
|
||||
export interface UnionPatternNode extends NamedNodeBase {
|
||||
type: SyntaxType.UnionPattern;
|
||||
argPatternNodes: (UnnamedNode<"("> | UnnamedNode<")"> | AnythingPatternNode | CharConstantExprNode | ListPatternNode | LowerPatternNode | NullaryConstructorArgumentPatternNode | NumberConstantExprNode | PatternNode | RecordPatternNode | StringConstantExprNode | TuplePatternNode | UnitExprNode)[];
|
||||
constructorNode: UpperCaseQidNode;
|
||||
}
|
||||
|
||||
export interface UnionVariantNode extends NamedNodeBase {
|
||||
type: SyntaxType.UnionVariant;
|
||||
nameNode: UpperCaseIdentifierNode;
|
||||
partNodes: (RecordTypeNode | TupleTypeNode | TypeExpressionNode | TypeRefNode | TypeVariableNode)[];
|
||||
}
|
||||
|
||||
export interface UnitExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.UnitExpr;
|
||||
}
|
||||
|
||||
export interface UpperCaseQidNode extends NamedNodeBase {
|
||||
type: SyntaxType.UpperCaseQid;
|
||||
}
|
||||
|
||||
export interface ValueDeclarationNode extends NamedNodeBase {
|
||||
type: SyntaxType.ValueDeclaration;
|
||||
bodyNode: AnonymousFunctionExprNode | BinOpExprNode | CaseOfExprNode | CharConstantExprNode | FieldAccessExprNode | FieldAccessorFunctionExprNode | FunctionCallExprNode | GlslCodeExprNode | IfElseExprNode | LetInExprNode | ListExprNode | NegateExprNode | NumberConstantExprNode | OperatorAsFunctionExprNode | ParenthesizedExprNode | RecordExprNode | StringConstantExprNode | TupleExprNode | UnitExprNode | ValueExprNode;
|
||||
functionDeclarationLeftNode?: FunctionDeclarationLeftNode;
|
||||
patternNode?: PatternNode;
|
||||
}
|
||||
|
||||
export interface ValueExprNode extends NamedNodeBase {
|
||||
type: SyntaxType.ValueExpr;
|
||||
nameNode: UpperCaseQidNode | ValueQidNode;
|
||||
}
|
||||
|
||||
export interface ValueQidNode extends NamedNodeBase {
|
||||
type: SyntaxType.ValueQid;
|
||||
}
|
||||
|
||||
export interface AliasNode extends NamedNodeBase {
|
||||
type: SyntaxType.Alias;
|
||||
}
|
||||
|
||||
export interface ArrowNode extends NamedNodeBase {
|
||||
type: SyntaxType.Arrow;
|
||||
}
|
||||
|
||||
export interface AsNode extends NamedNodeBase {
|
||||
type: SyntaxType.As;
|
||||
}
|
||||
|
||||
export interface BackslashNode extends NamedNodeBase {
|
||||
type: SyntaxType.Backslash;
|
||||
}
|
||||
|
||||
export interface CaseNode extends NamedNodeBase {
|
||||
type: SyntaxType.Case;
|
||||
}
|
||||
|
||||
export interface CloseCharNode extends NamedNodeBase {
|
||||
type: SyntaxType.CloseChar;
|
||||
}
|
||||
|
||||
export interface CloseQuoteNode extends NamedNodeBase {
|
||||
type: SyntaxType.CloseQuote;
|
||||
}
|
||||
|
||||
export interface ColonNode extends NamedNodeBase {
|
||||
type: SyntaxType.Colon;
|
||||
}
|
||||
|
||||
export interface DotNode extends NamedNodeBase {
|
||||
type: SyntaxType.Dot;
|
||||
}
|
||||
|
||||
export interface DoubleDotNode extends NamedNodeBase {
|
||||
type: SyntaxType.DoubleDot;
|
||||
}
|
||||
|
||||
export interface EffectNode extends NamedNodeBase {
|
||||
type: SyntaxType.Effect;
|
||||
}
|
||||
|
||||
export interface EqNode extends NamedNodeBase {
|
||||
type: SyntaxType.Eq;
|
||||
}
|
||||
|
||||
export interface ExposingNode extends NamedNodeBase {
|
||||
type: SyntaxType.Exposing;
|
||||
}
|
||||
|
||||
export interface GlslContentNode extends NamedNodeBase {
|
||||
type: SyntaxType.GlslContent;
|
||||
}
|
||||
|
||||
export interface ImportNode extends NamedNodeBase {
|
||||
type: SyntaxType.Import;
|
||||
}
|
||||
|
||||
export interface InfixNode extends NamedNodeBase {
|
||||
type: SyntaxType.Infix;
|
||||
}
|
||||
|
||||
export interface InvalidStringEscapeNode extends NamedNodeBase {
|
||||
type: SyntaxType.InvalidStringEscape;
|
||||
}
|
||||
|
||||
export interface LineCommentNode extends NamedNodeBase {
|
||||
type: SyntaxType.LineComment;
|
||||
}
|
||||
|
||||
export interface LowerCaseIdentifierNode extends NamedNodeBase {
|
||||
type: SyntaxType.LowerCaseIdentifier;
|
||||
}
|
||||
|
||||
export interface ModuleNode extends NamedNodeBase {
|
||||
type: SyntaxType.Module;
|
||||
}
|
||||
|
||||
export interface NumberLiteralNode extends NamedNodeBase {
|
||||
type: SyntaxType.NumberLiteral;
|
||||
}
|
||||
|
||||
export interface OfNode extends NamedNodeBase {
|
||||
type: SyntaxType.Of;
|
||||
}
|
||||
|
||||
export interface OpenCharNode extends NamedNodeBase {
|
||||
type: SyntaxType.OpenChar;
|
||||
}
|
||||
|
||||
export interface OpenQuoteNode extends NamedNodeBase {
|
||||
type: SyntaxType.OpenQuote;
|
||||
}
|
||||
|
||||
export interface PortNode extends NamedNodeBase {
|
||||
type: SyntaxType.Port;
|
||||
}
|
||||
|
||||
export interface RegularStringPartNode extends NamedNodeBase {
|
||||
type: SyntaxType.RegularStringPart;
|
||||
}
|
||||
|
||||
export interface StringEscapeNode extends NamedNodeBase {
|
||||
type: SyntaxType.StringEscape;
|
||||
}
|
||||
|
||||
export interface TypeNode extends NamedNodeBase {
|
||||
type: SyntaxType.Type;
|
||||
}
|
||||
|
||||
export interface UnderscoreNode extends NamedNodeBase {
|
||||
type: SyntaxType.Underscore;
|
||||
}
|
||||
|
||||
export interface UpperCaseIdentifierNode extends NamedNodeBase {
|
||||
type: SyntaxType.UpperCaseIdentifier;
|
||||
}
|
||||
|
||||
export interface WhereNode extends NamedNodeBase {
|
||||
type: SyntaxType.Where;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,496 @@
|
||||
#include "tree_sitter/parser.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define VEC_RESIZE(vec, _cap) \
|
||||
void *tmp = realloc((vec).data, (_cap) * sizeof((vec).data[0])); \
|
||||
assert(tmp != NULL); \
|
||||
(vec).data = tmp; \
|
||||
assert((vec).data != NULL); \
|
||||
(vec).cap = (_cap);
|
||||
|
||||
#define VEC_GROW(vec, _cap) \
|
||||
if ((vec).cap < (_cap)) { \
|
||||
VEC_RESIZE((vec), (_cap)); \
|
||||
}
|
||||
|
||||
#define VEC_PUSH(vec, el) \
|
||||
if ((vec).cap == (vec).len) { \
|
||||
VEC_RESIZE((vec), MAX(16, (vec).len * 2)); \
|
||||
} \
|
||||
(vec).data[(vec).len++] = (el);
|
||||
|
||||
#define VEC_POP(vec) (vec).len--;
|
||||
|
||||
#define VEC_BACK(vec) ((vec).data[(vec).len - 1])
|
||||
|
||||
#define VEC_FREE(vec) \
|
||||
{ \
|
||||
if ((vec).data != NULL) \
|
||||
free((vec).data); \
|
||||
}
|
||||
|
||||
#define VEC_CLEAR(vec) (vec).len = 0;
|
||||
|
||||
#define VEC_REVERSE(vec) \
|
||||
do { \
|
||||
if ((vec).len > 1) { \
|
||||
for (size_t i = 0, j = (vec).len - 1; i < j; i++, j--) { \
|
||||
uint8_t tmp = (vec).data[i]; \
|
||||
(vec).data[i] = (vec).data[j]; \
|
||||
(vec).data[j] = tmp; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
enum TokenType {
|
||||
VIRTUAL_END_DECL,
|
||||
VIRTUAL_OPEN_SECTION,
|
||||
VIRTUAL_END_SECTION,
|
||||
MINUS_WITHOUT_TRAILING_WHITESPACE,
|
||||
GLSL_CONTENT,
|
||||
BLOCK_COMMENT_CONTENT,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t cap;
|
||||
uint8_t *data;
|
||||
} vec;
|
||||
|
||||
typedef struct {
|
||||
uint32_t indent_length;
|
||||
vec indents;
|
||||
vec runback;
|
||||
} Scanner;
|
||||
|
||||
static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
|
||||
|
||||
static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
|
||||
|
||||
// > You can detect error recovery in the external scanner by the fact that
|
||||
// > _all_ tokens are considered valid at once.
|
||||
// https://github.com/tree-sitter/tree-sitter/pull/1783#issuecomment-1181011411
|
||||
static bool in_error_recovery(const bool *valid_symbols) {
|
||||
return (valid_symbols[VIRTUAL_END_DECL] &&
|
||||
valid_symbols[VIRTUAL_OPEN_SECTION] &&
|
||||
valid_symbols[VIRTUAL_END_SECTION] &&
|
||||
valid_symbols[MINUS_WITHOUT_TRAILING_WHITESPACE] &&
|
||||
valid_symbols[GLSL_CONTENT] &&
|
||||
valid_symbols[BLOCK_COMMENT_CONTENT]);
|
||||
}
|
||||
|
||||
static bool is_elm_space(TSLexer *lexer) {
|
||||
return lexer->lookahead == ' ' || lexer->lookahead == '\r' ||
|
||||
lexer->lookahead == '\n';
|
||||
}
|
||||
|
||||
static int checkForIn(TSLexer *lexer, const bool *valid_symbols) {
|
||||
// Are we at the end of a let (in) declaration
|
||||
if (valid_symbols[VIRTUAL_END_SECTION] && lexer->lookahead == 'i') {
|
||||
skip(lexer);
|
||||
|
||||
if (lexer->lookahead == 'n') {
|
||||
skip(lexer);
|
||||
if (is_elm_space(lexer) || lexer->eof(lexer)) {
|
||||
return 2; // Success
|
||||
}
|
||||
return 1; // Partial
|
||||
}
|
||||
return 1; // Partial
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool scan_block_comment(TSLexer *lexer) {
|
||||
lexer->mark_end(lexer);
|
||||
if (lexer->lookahead != '{') {
|
||||
return false;
|
||||
}
|
||||
|
||||
advance(lexer);
|
||||
if (lexer->lookahead != '-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
advance(lexer);
|
||||
|
||||
while (true) {
|
||||
switch (lexer->lookahead) {
|
||||
case '{':
|
||||
scan_block_comment(lexer);
|
||||
break;
|
||||
case '-':
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '}') {
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
return true;
|
||||
default:
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void advance_to_line_end(TSLexer *lexer) {
|
||||
while (true) {
|
||||
if (lexer->lookahead == '\n' || lexer->eof(lexer)) {
|
||||
break;
|
||||
}
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
|
||||
static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
|
||||
if (in_error_recovery(valid_symbols)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First handle eventual runback tokens, we saved on a previous scan op
|
||||
if (scanner->runback.len > 0 && VEC_BACK(scanner->runback) == 0 &&
|
||||
valid_symbols[VIRTUAL_END_DECL]) {
|
||||
VEC_POP(scanner->runback);
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
if (scanner->runback.len > 0 && VEC_BACK(scanner->runback) == 1 &&
|
||||
valid_symbols[VIRTUAL_END_SECTION]) {
|
||||
VEC_POP(scanner->runback);
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
VEC_CLEAR(scanner->runback);
|
||||
|
||||
// Check if we have newlines and how much indentation
|
||||
bool has_newline = false;
|
||||
bool found_in = false;
|
||||
bool can_call_mark_end = true;
|
||||
lexer->mark_end(lexer);
|
||||
while (true) {
|
||||
if (lexer->lookahead == ' ' || lexer->lookahead == '\r') {
|
||||
skip(lexer);
|
||||
} else if (lexer->lookahead == '\n') {
|
||||
skip(lexer);
|
||||
has_newline = true;
|
||||
while (true) {
|
||||
if (lexer->lookahead == ' ') {
|
||||
skip(lexer);
|
||||
} else {
|
||||
scanner->indent_length = lexer->get_column(lexer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!valid_symbols[BLOCK_COMMENT_CONTENT] &&
|
||||
lexer->lookahead == '-') {
|
||||
advance(lexer);
|
||||
int32_t lookahead = lexer->lookahead;
|
||||
|
||||
// Handle minus without a whitespace for negate
|
||||
if (valid_symbols[MINUS_WITHOUT_TRAILING_WHITESPACE] &&
|
||||
((lookahead >= 'a' && lookahead <= 'z') ||
|
||||
(lookahead >= 'A' && lookahead <= 'Z') || lookahead == '(')) {
|
||||
if (can_call_mark_end) {
|
||||
lexer->result_symbol = MINUS_WITHOUT_TRAILING_WHITESPACE;
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Scan past line comments. As far as the special token
|
||||
// types we're scanning for here are concerned line comments
|
||||
// are like whitespace. There is nothing useful to be
|
||||
// learned from, say, their indentation. So we advance past
|
||||
// them here.
|
||||
//
|
||||
// The one thing we need to keep in mind is that we should
|
||||
// not call `lexer->mark_end(lexer)` after this point, or
|
||||
// the comment will be lost.
|
||||
if (lookahead == '-' && has_newline) {
|
||||
can_call_mark_end = false;
|
||||
advance(lexer);
|
||||
advance_to_line_end(lexer);
|
||||
} else if (valid_symbols[BLOCK_COMMENT_CONTENT] &&
|
||||
lexer->lookahead == '}') {
|
||||
lexer->result_symbol = BLOCK_COMMENT_CONTENT;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (lexer->eof(lexer)) {
|
||||
if (valid_symbols[VIRTUAL_END_SECTION]) {
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
if (valid_symbols[VIRTUAL_END_DECL]) {
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForIn(lexer, valid_symbols) == 2) {
|
||||
if (has_newline) {
|
||||
found_in = true;
|
||||
} else {
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
VEC_POP(scanner->indents);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Open section if the grammar lets us but only push to indent stack if
|
||||
// we go further down in the stack
|
||||
if (valid_symbols[VIRTUAL_OPEN_SECTION] && !lexer->eof(lexer)) {
|
||||
VEC_PUSH(scanner->indents, lexer->get_column(lexer));
|
||||
lexer->result_symbol = VIRTUAL_OPEN_SECTION;
|
||||
return true;
|
||||
}
|
||||
if (valid_symbols[BLOCK_COMMENT_CONTENT]) {
|
||||
if (!can_call_mark_end) {
|
||||
return false;
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
while (true) {
|
||||
if (lexer->lookahead == '\0') {
|
||||
break;
|
||||
}
|
||||
if (lexer->lookahead != '{' && lexer->lookahead != '-') {
|
||||
advance(lexer);
|
||||
} else if (lexer->lookahead == '-') {
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '}') {
|
||||
break;
|
||||
}
|
||||
} else if (scan_block_comment(lexer)) {
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '-') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lexer->result_symbol = BLOCK_COMMENT_CONTENT;
|
||||
return true;
|
||||
}
|
||||
if (has_newline) {
|
||||
// We had a newline now it's time to check if we need to add
|
||||
// multiple tokens to get back up to the right level
|
||||
VEC_CLEAR(scanner->runback);
|
||||
|
||||
while (scanner->indent_length <= VEC_BACK(scanner->indents)) {
|
||||
if (scanner->indent_length == VEC_BACK(scanner->indents)) {
|
||||
if (found_in) {
|
||||
VEC_PUSH(scanner->runback, 1);
|
||||
found_in = false;
|
||||
break;
|
||||
}
|
||||
// Don't insert VIRTUAL_END_DECL when there is a line
|
||||
// comment incoming
|
||||
|
||||
if (lexer->lookahead == '-') {
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '-') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Don't insert VIRTUAL_END_DECL when there is a block
|
||||
// comment incoming
|
||||
if (lexer->lookahead == '{') {
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '-') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
VEC_PUSH(scanner->runback, 0);
|
||||
break;
|
||||
}
|
||||
if (scanner->indent_length < VEC_BACK(scanner->indents)) {
|
||||
VEC_POP(scanner->indents);
|
||||
VEC_PUSH(scanner->runback, 1);
|
||||
found_in = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Needed for some of the more weird cases where let is in the same
|
||||
// line as everything before the in in the next line
|
||||
if (found_in) {
|
||||
VEC_PUSH(scanner->runback, 1);
|
||||
found_in = false;
|
||||
}
|
||||
|
||||
// Our list is the wrong way around, reverse it
|
||||
VEC_REVERSE(scanner->runback);
|
||||
// Handle the first runback token if we have them, if there are more
|
||||
// they will be handled on the next scan operation
|
||||
if (scanner->runback.len > 0 && VEC_BACK(scanner->runback) == 0 &&
|
||||
valid_symbols[VIRTUAL_END_DECL]) {
|
||||
VEC_POP(scanner->runback);
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
if (scanner->runback.len > 0 && VEC_BACK(scanner->runback) == 1 &&
|
||||
valid_symbols[VIRTUAL_END_SECTION]) {
|
||||
VEC_POP(scanner->runback);
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
if (lexer->eof(lexer) && valid_symbols[VIRTUAL_END_SECTION]) {
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[GLSL_CONTENT]) {
|
||||
if (!can_call_mark_end) {
|
||||
return false;
|
||||
}
|
||||
lexer->result_symbol = GLSL_CONTENT;
|
||||
while (true) {
|
||||
switch (lexer->lookahead) {
|
||||
case '|':
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == ']') {
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
default:
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
// API
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This function allocates the persistent state of the parser that is passed
|
||||
* into the other API functions.
|
||||
*/
|
||||
void *tree_sitter_elm_external_scanner_create() {
|
||||
Scanner *scanner = (Scanner *)calloc(1, sizeof(Scanner));
|
||||
return scanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main logic entry point.
|
||||
* Since the state is a singular vector, it can just be cast and used directly.
|
||||
*/
|
||||
bool tree_sitter_elm_external_scanner_scan(void *payload, TSLexer *lexer,
|
||||
const bool *valid_symbols) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
return scan(scanner, lexer, valid_symbols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the current state to another location for later reuse.
|
||||
* This is normally more complex, but since this parser's state constists solely
|
||||
* of a vector of integers, it can just be copied.
|
||||
*/
|
||||
unsigned tree_sitter_elm_external_scanner_serialize(void *payload,
|
||||
char *buffer) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
size_t size = 0;
|
||||
|
||||
if (3 + scanner->indents.len + scanner->runback.len >=
|
||||
TREE_SITTER_SERIALIZATION_BUFFER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t runback_count = scanner->runback.len;
|
||||
if (runback_count > UINT8_MAX) {
|
||||
runback_count = UINT8_MAX;
|
||||
}
|
||||
buffer[size++] = (char)runback_count;
|
||||
|
||||
if (runback_count > 0) {
|
||||
memcpy(&buffer[size], scanner->runback.data, runback_count);
|
||||
}
|
||||
size += runback_count;
|
||||
|
||||
size_t indent_length_length = sizeof(scanner->indent_length);
|
||||
buffer[size++] = (char)indent_length_length;
|
||||
if (indent_length_length > 0) {
|
||||
memcpy(&buffer[size], &scanner->indent_length, indent_length_length);
|
||||
}
|
||||
size += indent_length_length;
|
||||
|
||||
int iter = 1;
|
||||
for (; iter != scanner->indents.len &&
|
||||
size < TREE_SITTER_SERIALIZATION_BUFFER_SIZE;
|
||||
++iter) {
|
||||
buffer[size++] = (char)scanner->indents.data[iter];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load another parser state into the currently active state.
|
||||
* `payload` is the state of the previous parser execution, while `buffer` is
|
||||
* the saved state of a different position (e.g. when doing incremental
|
||||
* parsing).
|
||||
*/
|
||||
void tree_sitter_elm_external_scanner_deserialize(void *payload,
|
||||
const char *buffer,
|
||||
unsigned length) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
VEC_CLEAR(scanner->runback);
|
||||
VEC_CLEAR(scanner->indents);
|
||||
VEC_PUSH(scanner->indents, 0);
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
size_t runback_count = (unsigned char)buffer[size++];
|
||||
VEC_GROW(scanner->runback, runback_count)
|
||||
if (runback_count > 0) {
|
||||
memcpy(scanner->runback.data, &buffer[size], runback_count);
|
||||
scanner->runback.len = runback_count;
|
||||
size += runback_count;
|
||||
}
|
||||
|
||||
size_t indent_length_length = (unsigned char)buffer[size++];
|
||||
if (indent_length_length > 0) {
|
||||
memcpy(&scanner->indent_length, &buffer[size], indent_length_length);
|
||||
size += indent_length_length;
|
||||
}
|
||||
|
||||
for (; size < length; size++) {
|
||||
VEC_PUSH(scanner->indents, (unsigned char)buffer[size]);
|
||||
}
|
||||
assert(size == length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the state.
|
||||
*/
|
||||
void tree_sitter_elm_external_scanner_destroy(void *payload) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
VEC_FREE(scanner->indents);
|
||||
VEC_FREE(scanner->runback);
|
||||
free(scanner);
|
||||
}
|
||||
@ -1,507 +0,0 @@
|
||||
#include <tree_sitter/parser.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cwctype>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
enum TokenType
|
||||
{
|
||||
VIRTUAL_END_DECL,
|
||||
VIRTUAL_OPEN_SECTION,
|
||||
VIRTUAL_END_SECTION,
|
||||
MINUS_WITHOUT_TRAILING_WHITESPACE,
|
||||
GLSL_CONTENT,
|
||||
BLOCK_COMMENT_CONTENT
|
||||
};
|
||||
|
||||
struct Scanner
|
||||
{
|
||||
Scanner() {}
|
||||
|
||||
unsigned serialize(char *buffer)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
size_t runback_count = runback.size();
|
||||
if (runback_count > UINT8_MAX)
|
||||
runback_count = UINT8_MAX;
|
||||
buffer[i++] = runback_count;
|
||||
|
||||
if (runback_count > 0)
|
||||
{
|
||||
memcpy(&buffer[i], runback.data(), runback_count);
|
||||
}
|
||||
i += runback_count;
|
||||
|
||||
size_t indent_length_length = sizeof(indent_length);
|
||||
buffer[i++] = indent_length_length;
|
||||
if (indent_length_length > 0)
|
||||
{
|
||||
memcpy(&buffer[i], &indent_length, indent_length_length);
|
||||
}
|
||||
i += indent_length_length;
|
||||
|
||||
vector<uint32_t>::iterator
|
||||
iter = indent_length_stack.begin() + 1,
|
||||
end = indent_length_stack.end();
|
||||
|
||||
for (; iter != end && i < TREE_SITTER_SERIALIZATION_BUFFER_SIZE; ++iter)
|
||||
{
|
||||
buffer[i++] = *iter;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void deserialize(const char *buffer, unsigned length)
|
||||
{
|
||||
runback.clear();
|
||||
indent_length_stack.clear();
|
||||
indent_length_stack.push_back(0);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
size_t runback_count = (uint8_t)buffer[i++];
|
||||
runback.resize(runback_count);
|
||||
if (runback_count > 0)
|
||||
{
|
||||
memcpy(runback.data(), &buffer[i], runback_count);
|
||||
}
|
||||
i += runback_count;
|
||||
|
||||
size_t indent_length_length = buffer[i++];
|
||||
if (indent_length_length > 0)
|
||||
{
|
||||
memcpy(&indent_length, &buffer[i], indent_length_length);
|
||||
}
|
||||
i += indent_length_length;
|
||||
|
||||
for (; i < length; i++)
|
||||
{
|
||||
indent_length_stack.push_back(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void advance(TSLexer *lexer)
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
|
||||
void skip(TSLexer *lexer)
|
||||
{
|
||||
lexer->advance(lexer, true);
|
||||
}
|
||||
|
||||
bool isElmSpace(TSLexer *lexer)
|
||||
{
|
||||
return lexer->lookahead == ' ' || lexer->lookahead == '\r' || lexer->lookahead == '\n';
|
||||
}
|
||||
|
||||
int checkForIn(TSLexer *lexer, const bool *valid_symbols)
|
||||
{
|
||||
// Are we at the end of a let (in) declaration
|
||||
if (valid_symbols[VIRTUAL_END_SECTION] && lexer->lookahead == 'i')
|
||||
{
|
||||
skip(lexer);
|
||||
|
||||
if (lexer->lookahead == 'n')
|
||||
{
|
||||
skip(lexer);
|
||||
if (isElmSpace(lexer) || lexer->eof(lexer))
|
||||
{
|
||||
return 2; // Success
|
||||
}
|
||||
return 1; // Partial
|
||||
}
|
||||
return 1; // Partial
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool scan_block_comment(TSLexer *lexer)
|
||||
{
|
||||
lexer->mark_end(lexer);
|
||||
if (lexer->lookahead != '{')
|
||||
return false;
|
||||
|
||||
advance(lexer);
|
||||
if (lexer->lookahead != '-')
|
||||
return false;
|
||||
|
||||
advance(lexer);
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (lexer->lookahead)
|
||||
{
|
||||
case '{':
|
||||
scan_block_comment(lexer);
|
||||
break;
|
||||
case '-':
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '}')
|
||||
{
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
return true;
|
||||
default:
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void advance_to_line_end(TSLexer *lexer)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
if (lexer->lookahead == '\n') {
|
||||
break;
|
||||
}
|
||||
else if (lexer->eof(lexer)) {
|
||||
break;
|
||||
} else {
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool scan(TSLexer *lexer, const bool *valid_symbols)
|
||||
{
|
||||
// First handle eventual runback tokens, we saved on a previous scan op
|
||||
if (!runback.empty() && runback.back() == 0 && valid_symbols[VIRTUAL_END_DECL])
|
||||
{
|
||||
runback.pop_back();
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
if (!runback.empty() && runback.back() == 1 && valid_symbols[VIRTUAL_END_SECTION])
|
||||
{
|
||||
runback.pop_back();
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
runback.clear();
|
||||
|
||||
// Check if we have newlines and how much indentation
|
||||
bool has_newline = false;
|
||||
bool found_in = false;
|
||||
bool can_call_mark_end = true;
|
||||
lexer->mark_end(lexer);
|
||||
while (true)
|
||||
{
|
||||
if (lexer->lookahead == ' ')
|
||||
{
|
||||
skip(lexer);
|
||||
}
|
||||
else if (lexer->lookahead == '\n')
|
||||
{
|
||||
skip(lexer);
|
||||
has_newline = true;
|
||||
while (true)
|
||||
{
|
||||
if (lexer->lookahead == ' ')
|
||||
{
|
||||
skip(lexer);
|
||||
}
|
||||
else
|
||||
{
|
||||
indent_length = lexer->get_column(lexer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!valid_symbols[BLOCK_COMMENT_CONTENT] && lexer->lookahead == '-')
|
||||
{
|
||||
|
||||
advance(lexer);
|
||||
int32_t lookahead = lexer->lookahead;
|
||||
|
||||
// Handle minus without a whitespace for negate
|
||||
if (valid_symbols[MINUS_WITHOUT_TRAILING_WHITESPACE]
|
||||
&& ((lookahead >= 'a' && lookahead <= 'z')
|
||||
|| (lookahead >= 'A' && lookahead <= 'Z')
|
||||
|| lookahead == '('))
|
||||
{
|
||||
if (can_call_mark_end)
|
||||
{
|
||||
lexer->result_symbol = MINUS_WITHOUT_TRAILING_WHITESPACE;
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Scan past line comments. As far as the special token
|
||||
// types we're scanning for here are concerned line comments
|
||||
// are like whitespace. There is nothing useful to be
|
||||
// learned from, say, their indentation. So we advance past
|
||||
// them here.
|
||||
//
|
||||
// The one thing we need to keep in mind is that we should
|
||||
// not call `lexer->mark_end(lexer)` after this point, or
|
||||
// the comment will be lost.
|
||||
else if (lookahead == '-' && has_newline)
|
||||
{
|
||||
can_call_mark_end = false;
|
||||
advance(lexer);
|
||||
advance_to_line_end(lexer);
|
||||
}
|
||||
else if (valid_symbols[BLOCK_COMMENT_CONTENT] && lexer->lookahead == '}')
|
||||
{
|
||||
lexer->result_symbol = BLOCK_COMMENT_CONTENT;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lexer->lookahead == '\r')
|
||||
{
|
||||
skip(lexer);
|
||||
}
|
||||
else if (lexer->eof(lexer))
|
||||
{
|
||||
if (valid_symbols[VIRTUAL_END_SECTION])
|
||||
{
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
if (valid_symbols[VIRTUAL_END_DECL])
|
||||
{
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForIn(lexer, valid_symbols) == 2)
|
||||
{
|
||||
if (has_newline)
|
||||
{
|
||||
found_in = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
indent_length_stack.pop_back();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Open section if the grammar lets us but only push to indent stack if we go further down in the stack
|
||||
if (valid_symbols[VIRTUAL_OPEN_SECTION] && !lexer->eof(lexer))
|
||||
{
|
||||
indent_length_stack.push_back(lexer->get_column(lexer));
|
||||
lexer->result_symbol = VIRTUAL_OPEN_SECTION;
|
||||
return true;
|
||||
}
|
||||
else if (valid_symbols[BLOCK_COMMENT_CONTENT])
|
||||
{
|
||||
if (!can_call_mark_end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
while (true)
|
||||
{
|
||||
if (lexer->lookahead == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (lexer->lookahead != '{' && lexer->lookahead != '-')
|
||||
{
|
||||
advance(lexer);
|
||||
}
|
||||
else if (lexer->lookahead == '-')
|
||||
{
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '}')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (scan_block_comment(lexer))
|
||||
{
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lexer->result_symbol = BLOCK_COMMENT_CONTENT;
|
||||
return true;
|
||||
}
|
||||
else if (has_newline)
|
||||
{
|
||||
// We had a newline now it's time to check if we need to add multiple tokens to get back up to the right level
|
||||
runback.clear();
|
||||
|
||||
while (indent_length <= indent_length_stack.back())
|
||||
{
|
||||
if (indent_length == indent_length_stack.back())
|
||||
{
|
||||
if (found_in)
|
||||
{
|
||||
runback.push_back(1);
|
||||
found_in = false;
|
||||
break;
|
||||
}
|
||||
// Don't insert VIRTUAL_END_DECL when there is a line comment incoming
|
||||
|
||||
if (lexer->lookahead == '-')
|
||||
{
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Don't insert VIRTUAL_END_DECL when there is a block comment incoming
|
||||
if (lexer->lookahead == '{')
|
||||
{
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
runback.push_back(0);
|
||||
break;
|
||||
}
|
||||
else if (indent_length < indent_length_stack.back())
|
||||
{
|
||||
indent_length_stack.pop_back();
|
||||
runback.push_back(1);
|
||||
found_in = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Needed for some of the more weird cases where let is in the same line as everything before the in in the next line
|
||||
if (found_in)
|
||||
{
|
||||
runback.push_back(1);
|
||||
found_in = false;
|
||||
}
|
||||
|
||||
// Our list is the wrong way around, reverse it
|
||||
std::reverse(runback.begin(), runback.end());
|
||||
// Handle the first runback token if we have them, if there are more they will be handled on the next scan operation
|
||||
if (!runback.empty() && runback.back() == 0 && valid_symbols[VIRTUAL_END_DECL])
|
||||
{
|
||||
runback.pop_back();
|
||||
lexer->result_symbol = VIRTUAL_END_DECL;
|
||||
return true;
|
||||
}
|
||||
else if (!runback.empty() && runback.back() == 1 && valid_symbols[VIRTUAL_END_SECTION])
|
||||
{
|
||||
runback.pop_back();
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
else if (lexer->eof(lexer) && valid_symbols[VIRTUAL_END_SECTION])
|
||||
{
|
||||
lexer->result_symbol = VIRTUAL_END_SECTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[GLSL_CONTENT])
|
||||
{
|
||||
if (!can_call_mark_end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
lexer->result_symbol = GLSL_CONTENT;
|
||||
while (true)
|
||||
{
|
||||
switch (lexer->lookahead)
|
||||
{
|
||||
case '|':
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == ']')
|
||||
{
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
default:
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The indention of the current line
|
||||
uint32_t indent_length;
|
||||
// Our indentation stack
|
||||
vector<uint32_t> indent_length_stack;
|
||||
// Stack of 0 - for possible VIRTUAL_END_DECL or 1 - for possible VIRTUAL_END_SECTION
|
||||
vector<uint8_t> runback;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void *tree_sitter_elm_external_scanner_create()
|
||||
{
|
||||
return new Scanner();
|
||||
}
|
||||
|
||||
bool tree_sitter_elm_external_scanner_scan(void *payload, TSLexer *lexer,
|
||||
const bool *valid_symbols)
|
||||
{
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
return scanner->scan(lexer, valid_symbols);
|
||||
}
|
||||
|
||||
unsigned tree_sitter_elm_external_scanner_serialize(void *payload, char *buffer)
|
||||
{
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
return scanner->serialize(buffer);
|
||||
}
|
||||
|
||||
void tree_sitter_elm_external_scanner_deserialize(void *payload, const char *buffer, unsigned length)
|
||||
{
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
scanner->deserialize(buffer, length);
|
||||
}
|
||||
|
||||
void tree_sitter_elm_external_scanner_destroy(void *payload)
|
||||
{
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
delete scanner;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue