Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ aml = "0.16.4"
base64 = { version = "0.22.1", default-features = false, features = ["alloc"] }
bit_field = "0.10.3"
bootloader = { version = "0.9.34", features = ["map_physical_memory"] }
chumsky = { version = "0.13.0", default-features = false }
geodate = { version = "0.5.0", default-features = false }
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
libm = "0.2.16"
Expand Down
129 changes: 67 additions & 62 deletions src/api/ini.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,78 @@
use alloc::collections::btree_map::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use chumsky::prelude::*;
use nom::IResult;
use nom::Parser;
use nom::branch::alt;
use nom::bytes::complete::escaped;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::character::complete::char;
use nom::character::complete::multispace1;
use nom::character::complete::not_line_ending;
use nom::character::complete::one_of;
use nom::character::complete::space0;
use nom::combinator::all_consuming;
use nom::combinator::map;
use nom::combinator::opt;
use nom::multi::many0;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::sequence::terminated;

type ConfigMap = BTreeMap<String, String>;
type ParseResult<'a> = ConfigMap;
type ParseError<'a> = extra::Err<Simple<'a, char>>;

fn parser<'a>() -> impl Parser<'a, &'a str, ParseResult<'a>, ParseError<'a>> {
let whitespace = one_of(" \t").repeated();
let newline = one_of("\n\r").repeated().at_least(1);
let key = text::ident();
let comment = just('#').then(none_of("\n\r").repeated()).ignored();

let quoted_val = none_of("\"").
repeated().
collect::<String>().
delimited_by(just('"'), just('"'));

let unquoted_val = none_of("\n\r#").
repeated().
collect::<String>();

let val = quoted_val.or(unquoted_val).map(|s| s.trim().to_string());

let pair = key.
then_ignore(whitespace).
then_ignore(just('=')).
then_ignore(whitespace).
then(val).
then_ignore(whitespace).
then_ignore(comment.or_not()).
map(|(k, v): (&str, String)| (k.to_string(), v));

let line = pair.
map(Some).
or(comment.to(None)).
or(whitespace.to(None));

line.separated_by(newline).
allow_trailing().
collect::<Vec<_>>().
map(|items| items.into_iter().flatten().collect())

fn parse_comment(input: &str) -> IResult<&str, &str> {
preceded(char('#'), not_line_ending).parse(input)
}

fn ignored(input: &str) -> IResult<&str, ()> {
map(many0(alt((multispace1, parse_comment))), |_| ()).parse(input)
}

fn parse_str(input: &str) -> IResult<&str, &str> {
delimited(
char('"'),
opt(escaped(
is_not("\\\""),
'\\',
one_of("nrt\"\\be")
)),
char('"')
).map(|res| res.unwrap_or("")).parse(input)
}

fn parse_val(input: &str) -> IResult<&str, &str> {
alt((parse_str, is_not(" \t\r\n#="))).parse(input)
}

fn parse_eq(input: &str) -> IResult<&str, &str> {
delimited(space0, tag("="), space0).parse(input)
}

fn parse_key(input: &str) -> IResult<&str, &str> {
is_not(" \t\r\n#=").parse(input)
}

fn parse_pair(input: &str) -> IResult<&str, (&str, &str)> {
preceded(
ignored,
separated_pair(parse_key, parse_eq, parse_val)
).parse(input)
}

fn parse_pairs(input: &str) -> IResult<&str, Vec<(&str, &str)>> {
terminated(many0(parse_pair), ignored).parse(input)
}

pub fn parse(input: &str) -> Option<ConfigMap> {
parser().parse(input).into_result().ok()
let (_, pairs) = all_consuming(parse_pairs).parse(input).ok()?;
let mut config = ConfigMap::new();
for (key, val) in pairs {
config.insert(key.to_string(), val.to_string());
}
Some(config)
}

#[test_case]
Expand Down Expand Up @@ -81,17 +108,6 @@ fn test_parse_with_empty_lines() {
assert_eq!(parse(input), Some(expected));
}

#[test_case]
fn test_parse_with_spaces_in_values() {
let input = "key1= value with spaces \nkey2=another value";
let expected = BTreeMap::from([
("key1".to_string(), "value with spaces".to_string()),
("key2".to_string(), "another value".to_string()),
]);

assert_eq!(parse(input), Some(expected));
}

#[test_case]
fn test_parse_with_crlf() {
let input = "key1=value1\r\nkey2=value2\r\n";
Expand All @@ -103,17 +119,6 @@ fn test_parse_with_crlf() {
assert_eq!(parse(input), Some(expected));
}

#[test_case]
fn test_parse_with_empty_value() {
let input = "key1=\nkey2=value2";
let expected = BTreeMap::from([
("key1".to_string(), "".to_string()),
("key2".to_string(), "value2".to_string()),
]);

assert_eq!(parse(input), Some(expected));
}

#[test_case]
fn test_parse_with_special_chars() {
let input = "path=/usr/bin/test\nurl=https://example.com:8080";
Expand Down
64 changes: 46 additions & 18 deletions src/usr/brainfuck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ use crate::api::io;
use crate::api::process::ExitCode;

use alloc::vec::Vec;
use chumsky::prelude::*;
use nom::Err::{Error, Failure, Incomplete};
use nom::IResult;
use nom::Parser;
use nom::branch::alt;
use nom::character::complete::char;
use nom::character::complete::none_of;
use nom::combinator::all_consuming;
use nom::combinator::map;
use nom::combinator::value;
use nom::multi::many0;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;

const TAPE_LEN: usize = 30_000;

Expand All @@ -20,17 +32,33 @@ enum Instr {
Loop(Vec<Self>),
}

fn parser<'a>() -> impl Parser<'a, &'a str, Vec<Instr>, extra::Err<Rich<'a, char>>> {
let comment = none_of("<>+-,.[]").ignored();
recursive(|bf| choice((
just('<').to(Instr::Left),
just('>').to(Instr::Right),
just('+').to(Instr::Incr),
just('-').to(Instr::Decr),
just(',').to(Instr::Read),
just('.').to(Instr::Write),
bf.delimited_by(just('['), just(']')).map(Instr::Loop),
)).padded_by(comment.repeated()).repeated().collect())
fn ignored(input: &str) -> IResult<&str, ()> {
map(many0(none_of("<>+-,.[]")), |_| ()).parse(input)
}

fn instr(input: &str) -> IResult<&str, Instr> {
alt((
value(Instr::Left, char('<')),
value(Instr::Right, char('>')),
value(Instr::Incr, char('+')),
value(Instr::Decr, char('-')),
value(Instr::Read, char(',')),
value(Instr::Write, char('.')),
map(delimited(char('['), program, char(']')), Instr::Loop)
)).parse(input)
}

fn program(input: &str) -> IResult<&str, Vec<Instr>> {
preceded(ignored, many0(terminated(instr, ignored))).parse(input)
}

fn parse(input: &str) -> Result<Vec<Instr>, usize> {
match all_consuming(program).parse(input) {
Ok((_, ast)) => Ok(ast),
Err(Error(e)) => Err(input.len() - e.input.len()),
Err(Failure(e)) => Err(input.len() - e.input.len()),
Err(Incomplete(_)) => Err(input.len()),
}
}

fn eval(ast: &[Instr], ptr: &mut usize, tape: &mut [u8; TAPE_LEN]) {
Expand Down Expand Up @@ -81,18 +109,18 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
let reset = Style::reset();
let path = args[1];
if let Ok(buf) = fs::read_to_string(path) {
match parser().parse(&buf).into_result() {
match parse(&buf) {
Ok(ast) => eval(&ast, &mut 0, &mut [0; TAPE_LEN]),
Err(errs) => errs.into_iter().for_each(|e| {
let (row, col) = pos(&buf, e.span().start);
Err(i) => {
let (row, col) = pos(&buf, i);
error!("Unexpected token at {path}:{row}:{col}");

let line = buf.lines().nth(row - 1).unwrap();
let space = " ".repeat(col - 1);
let arrow = "^".repeat(e.span().end - e.span().start);
let arrow = "^";
let reason = "unexpected token";
eprintln!("\n{line}\n{space}{error}{arrow} {reason}{reset}");
})
}
};
Ok(())
} else {
Expand All @@ -119,5 +147,5 @@ fn test_parser() {
Instr::Incr, Instr::Incr, Instr::Incr, Instr::Incr, Instr::Incr,
Instr::Loop(vec![Instr::Decr])
];
assert_eq!(parser().parse(src).into_result(), Ok(ast));
assert_eq!(parse(src), Ok(ast));
}
10 changes: 4 additions & 6 deletions src/usr/lisp/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;

use nom::Err::Error;
use nom::IResult;
use nom::Parser;
use nom::branch::alt;
use nom::bytes::complete::escaped_transform;
use nom::bytes::complete::is_not;
Expand All @@ -23,15 +26,10 @@ use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::Err::Error;
use nom::IResult;
use nom::Parser;

// Whitespaces and comments are ignored
fn ignored(input: &str) -> IResult<&str, ()> {
recognize(
many0(alt((multispace1, parse_comment)))
).map(|_| ()).parse(input)
map(many0(alt((multispace1, parse_comment))), |_| ()).parse(input)
}

// https://docs.rs/nom/latest/nom/recipes/index.html#hexadecimal
Expand Down