schala/schala-lang/language/src/parser.rs

130 lines
3.3 KiB
Rust

extern crate nom;
use std::rc::Rc;
use std::str::FromStr;
use nom::IResult;
use nom::bytes::complete::{tag, take_while};
use nom::combinator::{map_res, value, opt};
use nom::multi::many1;
//use nom::error::{ParseError, ErrorKind};
use nom::branch::alt;
use crate::ast::*;
use crate::builtin::Builtin;
/*
#[derive(Debug, Clone)]
enum Prefix {
Plus,
Minus,
Bang,
}
*/
const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|";
fn parse_operator(input: &str) -> IResult<&str, BinOp> {
use nom::character::complete::one_of;
let (rest, op): (_, Vec<char>) = many1(one_of(OPERATOR_CHARS))(input)?;
let sigil: String = op.into_iter().collect();
Ok((rest, BinOp::from_sigil(&sigil)))
}
fn parse_bool_literal(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, value) = alt((
value(true, tag("true")),
value(false, tag("false"))
))(input)?;
Ok((rest, ExpressionKind::BoolLiteral(value)))
}
fn parse_binary_literal(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, _) = tag("0b")(input)?;
let (rest, n): (&str, u64) = map_res(
take_while(|c: char| c == '0' || c == '1'),
|hex_str: &str| u64::from_str_radix(hex_str, 2)
)(rest)?;
let expr = ExpressionKind::NatLiteral(n);
Ok((rest, expr))
}
fn parse_hex_literal(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, _) = tag("0x")(input)?;
let (rest, n): (&str, u64) = map_res(
take_while(|c: char| c.is_digit(16)),
|hex_str: &str| u64::from_str_radix(hex_str, 16)
)(rest)?;
let expr = ExpressionKind::NatLiteral(n);
Ok((rest, expr))
}
fn parse_string_literal(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, _) = nom::character::complete::char('"')(input)?;
let (rest, string_output) = nom::bytes::complete::take_until("\"")(rest)?;
let (rest, _) = nom::character::complete::char('"')(rest)?;
let expr = ExpressionKind::StringLiteral(Rc::new(string_output.to_string()));
Ok((rest, expr))
}
fn parse_literal(input: &str) -> IResult<&str, ExpressionKind> {
alt((
parse_string_literal,
parse_hex_literal,
parse_binary_literal,
parse_bool_literal
))(input)
}
fn paren_expr(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, _) = nom::character::complete::char('(')(input)?;
let (rest, inner) = expression_kind(rest)?;
let (rest, _) = nom::character::complete::char(')')(rest)?;
Ok((rest, inner))
}
fn prefix_op(input: &str) -> IResult<&str, PrefixOp> {
use nom::character::complete::char;
let (rest, sigil) = alt((
char('+'),
char('-'),
char('!')
))(input)?;
let op = PrefixOp::from_str(&sigil.to_string()).unwrap();
Ok((rest, op))
/*
alt((
value(Plus, char('+')),
value(Minus, char('-')),
value(Bang, char('!'))
))(input)
*/
}
fn prefix_expr(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, pfx) = opt(prefix_op)(input)?;
let (rest, result) = alt((
paren_expr,
parse_literal
))(rest)?;
match pfx {
None => Ok((rest, result)),
Some(pfx) => {
let exp = Expression { id: ItemId::new(0), kind: result, type_anno: None };
Ok((rest, ExpressionKind::PrefixExp(pfx, Box::new(exp))))
}
}
}
fn expression_kind(input: &str) -> IResult<&str, ExpressionKind> {
prefix_expr(input)
}
pub fn perform_parsing(input: &str) -> Result<String, String> {
let output = expression_kind(input);
Ok(format!("{:?}", output))
}