6 releases

0.3.0 Jul 19, 2022
0.2.0 Mar 18, 2022
0.1.3 Sep 24, 2021
0.1.2 Jul 18, 2021
0.1.1 Jun 2, 2021

#194 in Programming languages

MIT license

90KB
2.5K SLoC

Parser for Leap language.

Links:

Leap language.

Leap is a light, simple language for describing data structures.

Supported data types:

  • str - utf-8 string
  • int - 64-bit integer number
  • float - 64-bit floating point number
  • bool - boolean type
  • list - array of values
  • struct - user defined type with fields
  • enum - user defined type with multiple variants

Naming

All user defined names use kebab case (all letters are lower case, separated with -), eg.: user-auth, article-title, some-long-long-long-name:

  • name should start with a letter and can contain numbers
  • words in the name are separated with a single -

List

List defines array of values and accept single type argument for the type of elements:

  • list[int] - list of integers
  • list[user] - list of user structs
  • list[list[string]] - list of lists of strings

Struct

Struct is a user defined type, can have zero or more fields, and can have type arguments for generict values.

Example:

.struct user
    name: str
    age: int
    address: str
    tags: list[str]
    active: bool

here user.name is string, and user.tags is list of strings

Empty struct with no fields:

.struct none

Struct with type argument:

.struct some[t]
    value: t

here t is a type argument, and if it will be applied as str, value will become str

Enum

Enum is a user defined type, which describes which variants it can be, only structs can be variants of enum, enum can have type arguments.

Example:

.enum response
    user
    none

here response can be either user or none struct

Variants can be named:

.enum account
    admin: user
    customer: user

here variant names allow to avoid name conflict, as both variants admin and customer use same type user.

Enum with type argument:

.enum option[t]
    some[t]
    none

here t is a type argument, and if it will applied as int, some[t] variant will become some[int]

Type arguments

Types can have type arguments for generic values. If there is multiple type arguments, they separated with spaces:

.struct some-struct[a b c]
    value-a: a
    value-b: b
    value-c: c
    value-d: other-struct[a b list[c]]
    value-e: some[int]

here a, b, c is type arguments, which should be applied in order to use type, for example some-struct[int int str], in this case value-a will have int type, and value-d will have other-struct[int int list[str]] type. value-e have type some[int], which is some[t] with t applied as int.

Comments

Comments start with /-- and can be placed on separate line, or at the end of the line:

/-- some comment about page struct
.struct page[t]
    items: list[t] /-- other comment about items of page
    /-- comment about page additional info
    total-count: int

Example

Lets model types which can be used for REST API of blog engine:

/-- general types
.struct none

.struct some[t]
    value: t

.enum option[t]
    none
    some[t]

.enum result[t e]
    ok: some[t]
    err: some[e]

/-- api types
.struct page[t]
    value: t
    total-count: option[int]

.struct user
    id: int
    name: str
    email: str

.struct article
    id: int
    author: user
    title: str
    text: str
    tags: list[str]

here for our api:

  • for every request api returns result[t str], t for correct response or str for error (string with error message)
  • GET /users/7 will return result[user str], which allows to get info about user by id on success or error message
  • GET /articles will return result[page[article] str], which allows to get paged list of articles on success or error message
  • page.total-count is optional, if total-count is unknown it will be equal to none, otherwise some[int]

Example usage

Cargo.toml

[dependencies]
leap-lang = "0.2"

main.rs

use leap_lang::parser::parser::Parser;

fn main() {
    let types = Parser::parse("
        .enum enum1
        .struct struct1
        .struct struct2
            v1: int
    ").unwrap();
    for t in types {
        println!("name: {}", t.name());
    }
    // output:
    //
    // name: enum1
    // name: struct1
    // name: struct2
}

No runtime deps