Skip to content

Commit fb0b30c

Browse files
committed
merge: branch 'core-poc'
2 parents 9ecf9e1 + e4dc2c2 commit fb0b30c

File tree

8 files changed

+633
-2
lines changed

8 files changed

+633
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
nom = "7"
9+
nom = {"version" = "7", features = ["alloc"]}

src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#![allow(unused_variables, dead_code)]
2+
3+
mod parse;
14
mod face;
25
mod core;
36

src/parse/ast.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
use std::fmt;
2+
3+
#[derive(PartialEq, Debug)]
4+
pub struct TypedVar {
5+
pub var: String,
6+
pub typ: Option<String>,
7+
}
8+
9+
impl fmt::Display for TypedVar {
10+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11+
write!(f, "{}", self.var)?;
12+
if let Some(typ) = &self.typ {
13+
write!(f, ":{}", typ)?;
14+
}
15+
Ok(())
16+
}
17+
}
18+
19+
#[derive(PartialEq, Debug)]
20+
pub struct FuncData {
21+
pub arg: TypedVar,
22+
pub body: Box<Term>,
23+
}
24+
25+
impl fmt::Display for FuncData {
26+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
write!(f, "({}.{})", self.arg, self.body)
28+
}
29+
}
30+
31+
#[derive(PartialEq, Debug)]
32+
pub struct ApplyData {
33+
pub func: Box<Term>,
34+
pub arg: Box<Term>,
35+
}
36+
37+
impl fmt::Display for ApplyData {
38+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39+
write!(f, "{} {}", self.func, self.arg)
40+
}
41+
}
42+
43+
#[derive(PartialEq, Debug)]
44+
pub enum Term {
45+
Int(i64),
46+
Str(String),
47+
Var(String), // The name of the variable
48+
Func(FuncData),
49+
Apply(ApplyData),
50+
}
51+
52+
impl fmt::Display for Term {
53+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54+
match self {
55+
Term::Int(num) => write!(f, "{}", num),
56+
Term::Str(s) => write!(f, "\"{}\"", s),
57+
Term::Var(var) => write!(f, "{}", var),
58+
Term::Func(func) => write!(f, "{}", func),
59+
Term::Apply(apply) => write!(f, "{}", apply),
60+
}
61+
}
62+
}
63+
64+
#[derive(PartialEq, Debug)]
65+
pub struct RawAst {
66+
pub expr: Term,
67+
}
68+
69+
impl fmt::Display for RawAst {
70+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71+
write!(f, "{}", self.expr)
72+
}
73+
}
74+
75+
#[cfg(test)]
76+
mod tests {
77+
use super::*;
78+
79+
#[test]
80+
fn test_typed_var_display() {
81+
let typed_var = TypedVar {
82+
var: "x".to_string(),
83+
typ: Some("Int".to_string()),
84+
};
85+
assert_eq!(format!("{}", typed_var), "x:Int");
86+
87+
let typed_var = TypedVar {
88+
var: "y".to_string(),
89+
typ: None,
90+
};
91+
assert_eq!(format!("{}", typed_var), "y");
92+
}
93+
94+
#[test]
95+
fn test_func_data_display() {
96+
let typed_var = TypedVar {
97+
var: "x".to_string(),
98+
typ: Some("Int".to_string()),
99+
};
100+
let term = Term::Int(42);
101+
let func_data = FuncData {
102+
arg: typed_var,
103+
body: Box::new(term),
104+
};
105+
assert_eq!(format!("{}", func_data), "(x:Int.42)");
106+
}
107+
108+
#[test]
109+
fn test_apply_data_display() {
110+
let term1 = Term::Var("f".to_string());
111+
let term2 = Term::Int(42);
112+
let apply_data = ApplyData {
113+
func: Box::new(term1),
114+
arg: Box::new(term2),
115+
};
116+
assert_eq!(format!("{}", apply_data), "f 42");
117+
}
118+
119+
#[test]
120+
fn test_term_display() {
121+
let term = Term::Int(42);
122+
assert_eq!(format!("{}", term), "42");
123+
124+
let term = Term::Str("Hello, world!".to_string());
125+
assert_eq!(format!("{}", term), "\"Hello, world!\"");
126+
127+
let term = Term::Var("x".to_string());
128+
assert_eq!(format!("{}", term), "x");
129+
130+
let typed_var = TypedVar {
131+
var: "y".to_string(),
132+
typ: None,
133+
};
134+
let term = Term::Func(FuncData {
135+
arg: typed_var,
136+
body: Box::new(Term::Int(42)),
137+
});
138+
assert_eq!(format!("{}", term), "(y.42)");
139+
140+
let term1 = Term::Var("f".to_string());
141+
let term2 = Term::Int(42);
142+
let apply_data = ApplyData {
143+
func: Box::new(term1),
144+
arg: Box::new(term2),
145+
};
146+
let term = Term::Apply(apply_data);
147+
assert_eq!(format!("{}", term), "f 42");
148+
}
149+
150+
#[test]
151+
fn test_raw_ast_display() {
152+
let term1 = Term::Var("add".to_string());
153+
let term2 = Term::Int(42);
154+
let apply_data = ApplyData {
155+
func: Box::new(term1),
156+
arg: Box::new(term2),
157+
};
158+
let raw_ast = RawAst {
159+
expr: Term::Apply(apply_data),
160+
};
161+
assert_eq!(format!("{}", raw_ast), "add 42");
162+
}
163+
}

src/parse/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub mod ast;
2+
pub mod number;
3+
pub mod parse;
4+
pub mod string;

src/parse/number.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use nom::{
2+
branch::alt,
3+
bytes::complete::{tag, tag_no_case},
4+
character::complete::one_of,
5+
combinator::{map_res, recognize},
6+
error::ParseError,
7+
multi::{many0, many1},
8+
sequence::{pair, preceded, terminated},
9+
Err, IResult, Parser,
10+
};
11+
12+
pub fn number(input: &str) -> IResult<&str, i64> {
13+
alt((
14+
match_base_n("b", 2),
15+
match_base_n("o", 8),
16+
match_base_n("d", 10),
17+
match_base_n("x", 16),
18+
))(input)
19+
}
20+
21+
fn match_base_n(c: &str, base: u32) -> impl Fn(&str) -> IResult<&str, i64> + '_ {
22+
let index: usize = (base + base.saturating_sub(10)) as usize;
23+
move |i: &str| {
24+
map_res(
25+
preceded(
26+
opt_if(base == 10, pair(tag("0"), tag_no_case(c))),
27+
recognize(many1(terminated(
28+
one_of(&"0123456789aAbBcCdDeEfF"[0..index]),
29+
many0(tag("_")),
30+
))),
31+
),
32+
|out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), base),
33+
)(i)
34+
}
35+
}
36+
37+
fn opt_if<I: Clone, O, E: ParseError<I>, F>(
38+
b: bool,
39+
mut f: F,
40+
) -> impl FnMut(I) -> IResult<I, Option<O>, E>
41+
where
42+
F: Parser<I, O, E>,
43+
{
44+
move |input: I| {
45+
let i = input.clone();
46+
match (f.parse(input), b) {
47+
(Ok((i, o)), _) => Ok((i, Some(o))),
48+
(Err(Err::Error(_)), true) => Ok((i, None)),
49+
(Err(e), _) => Err(e),
50+
}
51+
}
52+
}
53+
54+
#[cfg(test)]
55+
mod tests {
56+
use super::*;
57+
58+
#[test]
59+
fn test_parse_binary_number() {
60+
let input = "0b101";
61+
let (input, result) = number(input).unwrap();
62+
assert_eq!(input, "");
63+
assert_eq!(result, 0b101);
64+
}
65+
}

0 commit comments

Comments
 (0)