Using the Parser#
Using the API directly provides us with a more fine-grained control over the parsing process. It allows us to parse not just the input as a top-level source unit, but also individual constructs like contracts, various definitions, and even expressions.
Parsing Source Files#
Let's start with this simple source file, that contains a single contract:
We begin by creating a Language
object with a specified version. This is an entry point for our parser API. Then we can use it to parse the source file, specifying the top-level nonterminal to parse:
import assert from "node:assert";
import { Language } from "@nomicfoundation/slang/language";
import { NonterminalKind, TerminalKind } from "@nomicfoundation/slang/kinds";
import { NonterminalNode } from "@nomicfoundation/slang/cst";
const language = new Language("0.8.0");
const parseOutput = language.parse(NonterminalKind.ContractDefinition, source);
Checking for Syntax Errors#
If the file has errors, we can get them from the ParseOutput
type, and print them out:
for (const error of parseOutput.errors()) {
console.error(`Error at byte offset ${error.textRange().start.utf8}: ${error.message()}`);
}
Otherwise, we can check if input is valid using this helpful utility:
Inspecting the Parse Tree#
Now, let's try to inspect the resulting CST, and iterate on its children:
const contract = parseOutput.tree();
assert(contract instanceof NonterminalNode);
assert.equal(contract.kind, NonterminalKind.ContractDefinition);
const contractChildren = contract.children();
assert.equal(contractChildren.length, 7);
const [contractKeyword, firstSpace, contractName, secondSpace, openBrace, members, closeBrace] = contractChildren;
assert.equal(contractKeyword?.kind, TerminalKind.ContractKeyword);
assert.equal(firstSpace?.kind, TerminalKind.Whitespace);
assert.equal(contractName?.kind, TerminalKind.Identifier);
assert.equal(secondSpace?.kind, TerminalKind.Whitespace);
assert.equal(openBrace?.kind, TerminalKind.OpenBrace);
assert.equal(members?.kind, NonterminalKind.ContractMembers);
assert.equal(closeBrace?.kind, TerminalKind.CloseBrace);
Additionally, we can convert the CST node back into the input string: