mirror of
https://github.com/Noratrieb/config-language.git
synced 2026-01-14 16:45:06 +01:00
stuff
This commit is contained in:
commit
bce268cceb
13 changed files with 672 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
150
Cargo.lock
generated
Normal file
150
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "codespan"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config-language"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"codespan",
|
||||
"codespan-reporting",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "config-language"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
codespan = "0.11.1"
|
||||
codespan-reporting = "0.11.1"
|
||||
indexmap = "2.2.6"
|
||||
45
example-configs/kubernetes/deployment-dry.nix
Normal file
45
example-configs/kubernetes/deployment-dry.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
let
|
||||
trivialWebService = { name, selectorLabel, port, extraPodLabels ? { } }:
|
||||
[
|
||||
{
|
||||
apiVersion = "apps/v1";
|
||||
kind = "Deployment";
|
||||
metadata = {
|
||||
inherit name;
|
||||
};
|
||||
spec = {
|
||||
selector.matchLabels = selectorLabel;
|
||||
replicas = 2;
|
||||
template = {
|
||||
metadata.labels = selectorLabel // extraPodLabels;
|
||||
spec.containters = [
|
||||
{
|
||||
inherit name;
|
||||
image = "nginx";
|
||||
ports = [{ containerPort = port; }];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
apiVersion = "apps/v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
inherit name;
|
||||
labels = selectorLabel;
|
||||
};
|
||||
spec = {
|
||||
ports = { port = 80; protocol = "TCP"; };
|
||||
selector = selectorLabel;
|
||||
};
|
||||
}
|
||||
]
|
||||
;
|
||||
in
|
||||
trivialWebService {
|
||||
name = "my-nginx";
|
||||
selectorLabel = { run = "my-nginx"; };
|
||||
port = 80;
|
||||
extraPodLabels = { someOther = "label"; };
|
||||
}
|
||||
33
example-configs/kubernetes/deployment-raw.nix
Normal file
33
example-configs/kubernetes/deployment-raw.nix
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
[
|
||||
{
|
||||
apiVersion = "apps/v1";
|
||||
kind = "Deployment";
|
||||
metadata.name = "my-nginx";
|
||||
spec = {
|
||||
selector.matchLabels.run = "my-nginx";
|
||||
replicas = 2;
|
||||
template = {
|
||||
metadata.labels.run = "my-nginx";
|
||||
spec.containters = [
|
||||
{
|
||||
name = "my-nginx";
|
||||
image = "nginx";
|
||||
ports = [{ containerPort = 80; }];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
apiVersion = "apps/v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "my-nginx";
|
||||
labels.run = "my-nginx";
|
||||
};
|
||||
spec = {
|
||||
ports = { port = 80; protocol = "TCP"; };
|
||||
selector = { run = "my-nginx"; };
|
||||
};
|
||||
}
|
||||
]
|
||||
33
example-configs/kubernetes/deployment.yml
Normal file
33
example-configs/kubernetes/deployment.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# real k8s configs use --- and not a top-level array
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
run: my-nginx
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: my-nginx
|
||||
someOther: label
|
||||
spec:
|
||||
containers:
|
||||
- name: my-nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
selector:
|
||||
run: my-nginx
|
||||
34
example-configs/rust-cargo/Cargo.json
Normal file
34
example-configs/rust-cargo/Cargo.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"cargo-features": ["public-dependency"],
|
||||
"package": {
|
||||
"name": "std",
|
||||
"version": "0.0.0",
|
||||
"metadata": { "fortanix-sgx": { "threads": 125, "heap_size": 134217728 } }
|
||||
},
|
||||
"lib": { "crate-type": ["dylib", "rlib"] },
|
||||
"dependencies": {
|
||||
"alloc": { "path": "../alloc", "public": true },
|
||||
"something": "1.2.0",
|
||||
"std_detect": {
|
||||
"path": "../stdarch/crates/std_detect",
|
||||
"default-features": false,
|
||||
"features": ["rustc-dep-of-std"]
|
||||
},
|
||||
"target": {
|
||||
"cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))": {
|
||||
"dependencies": {
|
||||
"miniz_oxide": {
|
||||
"version": "0.7.0",
|
||||
"optional": true,
|
||||
"default-features": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"backtrace": ["gimli-symbolize", "miniz_oxide/rustc-dep-of-std"],
|
||||
"gimli-symbolize": []
|
||||
},
|
||||
"bench": [{ "name": "stdbenches", "path": "benches/lib.rs", "test": true }]
|
||||
}
|
||||
37
example-configs/rust-cargo/Cargo.toml
Normal file
37
example-configs/rust-cargo/Cargo.toml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# github.com/rust-lang/rust:library/std/Cargo.toml
|
||||
|
||||
cargo-features = ["public-dependency"]
|
||||
|
||||
[package]
|
||||
name = "std"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["dylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
alloc = { path = "../alloc", public = true }
|
||||
something = "1.2.0"
|
||||
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
|
||||
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
|
||||
|
||||
|
||||
[features]
|
||||
backtrace = [
|
||||
"gimli-symbolize",
|
||||
'miniz_oxide/rustc-dep-of-std',
|
||||
]
|
||||
gimli-symbolize = []
|
||||
|
||||
[package.metadata.fortanix-sgx]
|
||||
# Maximum possible number of threads when testing
|
||||
threads = 125
|
||||
# Maximum heap size
|
||||
heap_size = 0x8000000
|
||||
|
||||
[[bench]]
|
||||
name = "stdbenches"
|
||||
path = "benches/lib.rs"
|
||||
test = true
|
||||
38
example-configs/rust-cargo/Cargo.yml
Normal file
38
example-configs/rust-cargo/Cargo.yml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
cargo-features: [public-dependency]
|
||||
|
||||
package:
|
||||
name: std
|
||||
version: "0.0.0"
|
||||
metadata:
|
||||
fortanix-sgx:
|
||||
threads: 125
|
||||
heap_size: 0x8000000
|
||||
lib:
|
||||
crate-type:
|
||||
- dylib
|
||||
- rlib
|
||||
dependencies:
|
||||
alloc:
|
||||
path: ../alloc
|
||||
public: true
|
||||
something: "1.2.0"
|
||||
std_detect:
|
||||
path: ../stdarch/crates/std_detect
|
||||
default-features: false
|
||||
features: [rustc-dep-of-std]
|
||||
target:
|
||||
'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))':
|
||||
dependencies:
|
||||
miniz_oxide:
|
||||
version: "0.7.0"
|
||||
optional: true
|
||||
default-features: false
|
||||
features:
|
||||
backtrace:
|
||||
- gimli-symbolize
|
||||
- miniz_oxide/rustc-dep-of-std
|
||||
gimli-symbolize: []
|
||||
bench:
|
||||
- name: stdbenches
|
||||
path: benches/lib.rs
|
||||
test: true
|
||||
12
example.nc
Normal file
12
example.nc
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#type X = jsonSchema("https://kubernetesjsonschema.dev/v1.14.0/deployment-apps-v1.json")
|
||||
|
||||
[
|
||||
{
|
||||
apiVersion = "apps/v1",
|
||||
kind = "Deployment",
|
||||
metadata = {
|
||||
name = "my-nginx",
|
||||
}
|
||||
},
|
||||
"x",
|
||||
]
|
||||
45
src/lib.rs
Normal file
45
src/lib.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use codespan::Span;
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label},
|
||||
files::SimpleFiles,
|
||||
};
|
||||
|
||||
pub mod parser;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Parse(parser::Error),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn into_msg_and_span(self) -> (String, Span) {
|
||||
match self {
|
||||
Error::Parse(e) => e.into_msg_and_span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate(input: &str) -> Result<(), Error> {
|
||||
let expr = parser::parse(input).map_err(Error::Parse)?;
|
||||
dbg!(expr);
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn render_error(input: &str, error: Error) {
|
||||
let mut files = SimpleFiles::new();
|
||||
let file_id = files.add("example.nc", input);
|
||||
let (msg, span) = error.into_msg_and_span();
|
||||
let diagnostic = Diagnostic::error()
|
||||
.with_message(msg)
|
||||
.with_labels(vec![Label::primary(
|
||||
file_id,
|
||||
(span.start().to_usize())..span.end().to_usize(),
|
||||
)]);
|
||||
|
||||
let writer = codespan_reporting::term::termcolor::StandardStream::stderr(
|
||||
codespan_reporting::term::termcolor::ColorChoice::Always,
|
||||
);
|
||||
let config = codespan_reporting::term::Config::default();
|
||||
|
||||
codespan_reporting::term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
|
||||
}
|
||||
7
src/main.rs
Normal file
7
src/main.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
let input = std::fs::read_to_string("example.nc").unwrap();
|
||||
match config_language::evaluate(&input) {
|
||||
Ok(()) => {}
|
||||
Err(e) => config_language::render_error(&input, e),
|
||||
}
|
||||
}
|
||||
228
src/parser.rs
Normal file
228
src/parser.rs
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
use std::{iter::Peekable, vec};
|
||||
|
||||
use codespan::Span;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
SourceFileTooBig(usize),
|
||||
InvalidCharacter(char, Span),
|
||||
UnterminatedStringLiteral(Span),
|
||||
UnexpectedToken(String, Token),
|
||||
TooNested(Span),
|
||||
UnexpectedEndOfFile,
|
||||
}
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expr {
|
||||
Array(Vec<Expr>, Span),
|
||||
Object(IndexMap<String, Expr>, Span),
|
||||
String(String, Span),
|
||||
Ident(String, Span),
|
||||
}
|
||||
|
||||
struct TokenStream {
|
||||
tokens: Peekable<vec::IntoIter<Token>>,
|
||||
nesting: usize,
|
||||
}
|
||||
|
||||
impl TokenStream {
|
||||
fn peek(&mut self) -> Result<&Token> {
|
||||
self.tokens.peek().ok_or_else(|| Error::UnexpectedEndOfFile)
|
||||
}
|
||||
fn next(&mut self) -> Result<Token> {
|
||||
self.tokens.next().ok_or_else(|| Error::UnexpectedEndOfFile)
|
||||
}
|
||||
fn eat(&mut self, kind: TokenKind) -> Option<Token> {
|
||||
let next = self.peek().ok()?;
|
||||
if next.kind != kind {
|
||||
return None;
|
||||
}
|
||||
Some(self.next().unwrap())
|
||||
}
|
||||
fn expect(&mut self, kind: TokenKind) -> Result<Token> {
|
||||
let next = self.next()?;
|
||||
if next.kind != kind {
|
||||
return Err(Error::UnexpectedToken(format!("expected {kind:?}"), next));
|
||||
}
|
||||
Ok(next)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(input: &str) -> Result<Expr> {
|
||||
let tokens = lexer(input)?;
|
||||
dbg!(&tokens);
|
||||
let expr = parse_expr(&mut TokenStream {
|
||||
tokens: tokens.into_iter().peekable(),
|
||||
nesting: 0,
|
||||
})?;
|
||||
dbg!(&expr);
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_expr(t: &mut TokenStream) -> Result<Expr> {
|
||||
let token = t.next()?;
|
||||
if t.nesting > 50 {
|
||||
return Err(Error::TooNested(token.span));
|
||||
}
|
||||
let expr = match token.kind {
|
||||
TokenKind::BracketOpen => {
|
||||
let mut elems = vec![];
|
||||
let mut had_comma = true;
|
||||
loop {
|
||||
if let Ok(Token {
|
||||
kind: TokenKind::BracketClose,
|
||||
..
|
||||
}) = t.peek()
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if !had_comma {
|
||||
return Err(Error::UnexpectedToken("comma".to_owned(), t.next()?));
|
||||
}
|
||||
|
||||
t.nesting += 1;
|
||||
elems.push(parse_expr(t)?);
|
||||
t.nesting -= 1;
|
||||
|
||||
had_comma = t.eat(TokenKind::Comma).is_some();
|
||||
}
|
||||
|
||||
t.next()?;
|
||||
Expr::Array(elems, token.span)
|
||||
}
|
||||
TokenKind::BraceOpen => {
|
||||
let mut elems = IndexMap::new();
|
||||
let mut had_comma = true;
|
||||
loop {
|
||||
if let Ok(Token {
|
||||
kind: TokenKind::BraceClose,
|
||||
..
|
||||
}) = t.peek()
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if !had_comma {
|
||||
return Err(Error::UnexpectedToken("comma".to_owned(), t.next()?));
|
||||
}
|
||||
|
||||
let name_tok = t.next()?;
|
||||
let Token {
|
||||
kind: TokenKind::Ident(name),
|
||||
..
|
||||
} = name_tok
|
||||
else {
|
||||
return Err(Error::UnexpectedToken("expected name".into(), name_tok));
|
||||
};
|
||||
t.expect(TokenKind::Equal)?;
|
||||
t.nesting += 1;
|
||||
elems.insert(name, parse_expr(t)?);
|
||||
t.nesting -= 1;
|
||||
|
||||
had_comma = t.eat(TokenKind::Comma).is_some();
|
||||
}
|
||||
|
||||
t.next()?;
|
||||
Expr::Object(elems, token.span)
|
||||
}
|
||||
TokenKind::String(s) => Expr::String(s, token.span),
|
||||
TokenKind::Ident(s) => Expr::Ident(s, token.span),
|
||||
_ => return Err(Error::UnexpectedToken("expected expression".into(), token)),
|
||||
};
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Token {
|
||||
span: Span,
|
||||
kind: TokenKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum TokenKind {
|
||||
BracketOpen,
|
||||
BracketClose,
|
||||
BraceOpen,
|
||||
BraceClose,
|
||||
Equal,
|
||||
Comma,
|
||||
Ident(String),
|
||||
String(String),
|
||||
}
|
||||
|
||||
fn lexer(input_str: &str) -> Result<Vec<Token>> {
|
||||
if input_str.len() >= (u32::MAX as usize) {
|
||||
return Err(Error::SourceFileTooBig(input_str.len()));
|
||||
}
|
||||
let mut input = input_str.char_indices().peekable();
|
||||
|
||||
let mut tokens = vec![];
|
||||
|
||||
while let Some((idx, c)) = input.next() {
|
||||
let span = Span::new(idx as u32, (idx as u32) + 1);
|
||||
let mut simple = |kind| tokens.push(Token { span, kind });
|
||||
match c {
|
||||
c if c.is_whitespace() => {}
|
||||
'#' => loop {
|
||||
if let Some((_, '\n')) = input.next() {
|
||||
break;
|
||||
}
|
||||
},
|
||||
'[' => simple(TokenKind::BracketOpen),
|
||||
']' => simple(TokenKind::BracketClose),
|
||||
'{' => simple(TokenKind::BraceOpen),
|
||||
'}' => simple(TokenKind::BraceClose),
|
||||
'=' => simple(TokenKind::Equal),
|
||||
',' => simple(TokenKind::Comma),
|
||||
'"' => loop {
|
||||
match input.next() {
|
||||
None => return Err(Error::UnterminatedStringLiteral(span)),
|
||||
Some((next_idx, '"')) => {
|
||||
let s = &input_str[(idx + 1)..next_idx];
|
||||
tokens.push(Token {
|
||||
span: Span::new(idx as u32, next_idx as u32),
|
||||
kind: TokenKind::String(s.to_owned()),
|
||||
});
|
||||
break;
|
||||
}
|
||||
Some(_) => {}
|
||||
}
|
||||
},
|
||||
c if c.is_alphabetic() => {
|
||||
while let Some((next_idx, c)) = input.peek() {
|
||||
if !c.is_alphanumeric() {
|
||||
let s = &input_str[idx..*next_idx];
|
||||
tokens.push(Token {
|
||||
span: Span::new(idx as u32, *next_idx as u32),
|
||||
kind: TokenKind::Ident(s.to_owned()),
|
||||
});
|
||||
break;
|
||||
}
|
||||
input.next();
|
||||
}
|
||||
}
|
||||
c => return Err(Error::InvalidCharacter(c, span)),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub(crate) fn into_msg_and_span(self) -> (String, Span) {
|
||||
match self {
|
||||
Error::SourceFileTooBig(_) => ("source file bigger than 4GB".into(), Span::default()),
|
||||
Error::InvalidCharacter(c, sp) => (format!("invalid character: {c}"), sp),
|
||||
Error::UnterminatedStringLiteral(sp) => (format!("unterminated string literal"), sp),
|
||||
Error::UnexpectedToken(expected, tok) => {
|
||||
(format!("unexpected token, expected {expected}"), tok.span)
|
||||
}
|
||||
Error::TooNested(sp) => ("too nested".to_owned(), sp),
|
||||
Error::UnexpectedEndOfFile => ("unexpected end of file".to_owned(), Span::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue