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 Parser
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 { Parser } from "@nomicfoundation/slang/parser";
import {
assertIsNonterminalNode,
assertIsTerminalNode,
NonterminalKind,
TerminalKind,
} from "@nomicfoundation/slang/cst";
const parser = Parser.create("0.8.0");
const parseOutput = parser.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;
assertIsNonterminalNode(contract, NonterminalKind.ContractDefinition);
const contractChildren = contract.children;
assert.equal(contractChildren.length, 7);
const [contractKeyword, firstSpace, contractName, secondSpace, openBrace, members, closeBrace] = contractChildren;
assertIsTerminalNode(contractKeyword!.node, TerminalKind.ContractKeyword, "contract");
assertIsTerminalNode(firstSpace!.node, TerminalKind.Whitespace, " ");
assertIsTerminalNode(contractName!.node, TerminalKind.Identifier, "Foo");
assertIsTerminalNode(secondSpace!.node, TerminalKind.Whitespace, " ");
assertIsTerminalNode(openBrace!.node, TerminalKind.OpenBrace, "{");
assertIsNonterminalNode(members!.node, NonterminalKind.ContractMembers);
assertIsTerminalNode(closeBrace!.node, TerminalKind.CloseBrace, "}");
Additionally, we can convert the CST node back into the input string: