Skip to content

Ladle.toml

Kyle Brown edited this page Apr 22, 2020 · 7 revisions

The ladle.toml file is the core of a language syntax specification and contains all of the configuration and meta-data for the specification as a whole.

Language

The language section identifies the language being specified using the following fields.

Name Examples Description
name Java, Python The name of the language
domain java.com, python.org The domain that authoritatively represents this language
extension java, py The file extension that is associated with this language

Specification

The specification section contains meta-data about the specification itself as a distinct entity from the language.

Name Required Description
name yes The name of this specification, which is not required to be different from the language name
domain yes The domain associated with this specification, this will be a domain name controlled by your organization
description no A description string for this specification, it should ideally describe the nature of this specification as it relates to the language
licenses no A list of paths to licenses that the specification is available under
authors no A list of names of the authors of this specification
lexer.path no The path of the lexer file
parser.path no The path of the parser file (requires lexer.path)

Version

The version section describes how the specification is versioned and what the current version is. Specifications can be versioned in one of two different ways: canonically or non-canonically. A specification is canonical if it meets the following criteria.

  1. The specification represents the source of truth for the language officially
  2. The versioning of this specification represents the versioning of the language
  3. Specification publisher domain is the language domain

The version.number field must be defined for both types of versioning as it represents the specification itself.

The field version.canonical defaults to being true, non-canonical languages must set it to false.

When version.canonical is false, the field version.canon_range must be defined and indicate which canonical versions of the language the spec applies to.

Example Non-Canonical Version

[spec.version]
canonical = false
number = "0.1.0"
canon_range = { min = "3.7.1", max = "3.7.3" }

Tests

The test sections define specific tests that help verify that the specification is correct. Multiple different types of tests will be supported.

Simple Tests

type fields description
lexing.accept input.accepts, input.rejects Verifies that the lexer rejects and accepts the provided inputs correctly, without validating the generated token stream
lexing.match input.pattern, output.pattern Identifies all pairs of files matching the input and output patterns and then verifies that those input files generate the matching token stream files
lexing.match cases Goes through the cases list and runs the tokenizer on the input for the case and verifies that it matches the output token stream files
parsing.accept input.accepts, input.rejects Verifies that the parser rejects and accepts the provided input files correctly, without validating the generated parse tree
parsing.match input.pattern, output.pattern Identifies all pairs of files matching the input and output patterns and then verifies that those input files generate the corresponding parse tree files
parsing.match cases Goes through the cases list and runs the parser on the input for the case and verifies that it matches the output parse tree files

Compatibility Tests

Compatibility or compliance tests verify that two specs are consistent in some way.

Note: Specifications can be tested for compatibility against previous versions of themselves to create enhanced regression testing.

type fields description
lexing.compat.expand other.name, other.domain, other.version Collects all lexing.accept, and lexing.match tests from both this and the other spec. Checks that this spec accepts all inputs the other accepts, and that the other spec rejects all inputs this spec rejects
lexing.compat.shrink other.name, other.domain, other.version Collects all lexing.accept, and lexing.match tests from both this and the other spec. Checks that this spec rejects all inputs the other rejects, and that the other spec accepts all inputs this spec accepts

Examples

Non-Canonical 3rd-Party Specification

Often languages will be specified in ladle by parties that do not represent the individuals or organizations that control a given language.

These specifications are Non-Canonical, because they are not the source of truth for that language, and 3rd-Party, because they are developed by a party other than the languages primary organization.

[language]
name = "Python"
domain = "python.org"
extension = "py"

[spec]
name = "Python3.7"
domain = "welikepython.org"
licenses = ["./LICENSE.txt"]
authors = ["John Doe", "Jessica Smith"]

lexer.path = "./python37_lexer.ladle"
parser.path = "./python37_parser.ladle"

[spec.version]
canonical = false
number = "0.1.0"
canon_range = { min = "3.7.1", max = "3.7.3" }

[[test]]
type = "lexing.accept"
input.accepts = ["./tests/lex_accept/accept_*.txt"]
input.rejects = ["./tests/lex_accept/reject_*.txt"]

[[test]]
type = "lexing.match"
input.pattern = "./tests/lex_match/input_*.txt"
output.pattern = "./tests/lex_match/output_*.txt"

Simple Language Example

This example is a work-in-progress.

[language]
name = "MyLang"
domain = "mylang.org"
extension = "myl"

[spec]
name = "MyLang-Spec"
domain = "mylang.org"
licenses = ["./LICENSE.txt"]
authors = ["John Doe", "Jessica Smith"]

version.number = "0.1.0"

lexer.path = "./lexer.ladle"
parser.path = "./parser.ladle"

[[test]]
type = "lexing.match"
input.pattern = "./tests/lex_match/input_*.txt"
output.pattern = "./tests/lex_match/output_*.txt"

Flask-like Template Language Example

[language]
name = "Python-Template"
domain = "welikepython.com"
extension = "html"

[spec]
name = "Python3.7"
domain = "welikepython.org"
licenses = ["./LICENSE.txt"]
authors = ["John Doe", "Jessica Smith"]
version.number = "1.2.0"

# These definitions can now make use of the dependencies in scope
lexer.path = "./lexer.ladle"
parser.path = "./parser.ladle"

[[dependencies]]
name = "HTML"
domain = "w3.org"
version = "1.3.0"

[[dependencies]]
name = "Python"
domain = "python.org"
version = "3.7.2"

[[test]]
type = "parsing.expand"
other.name = "HTML"
other.version = "1.3.0"

[[test]]
type = "parsing.expand"
other.name = "Python"
other.version = "1.3.0"