feat: Add native u120 numbers

This commit is contained in:
Nicolas Abril 2022-11-15 17:37:55 +01:00
parent 2c9285ab94
commit 2e41571966
17 changed files with 182 additions and 106 deletions

View File

@ -130,10 +130,10 @@ fn codegen_all_expr(
match &expr.data {
Typ => mk_quoted_ctr(eval_ctr(quote, TermTag::Typ), vec![span_to_num(expr.span)]),
NumType(desugared::NumType::U60) => {
NumType(kind_tree::NumType::U60) => {
mk_quoted_ctr(eval_ctr(quote, TermTag::U60), vec![span_to_num(expr.span)])
}
NumType(desugared::NumType::U120) => todo!(),
NumType(kind_tree::NumType::U120) => todo!(),
Var(ident) => {
if quote && !lhs {
set_origin(ident)
@ -241,11 +241,11 @@ fn codegen_all_expr(
codegen_all_expr(lhs_rule, lhs, num, quote, inside),
],
),
Num(desugared::Num::U60(n)) => mk_quoted_ctr(
Num(kind_tree::Number::U60(n)) => mk_quoted_ctr(
eval_ctr(quote, TermTag::Num),
vec![span_to_num(expr.span), mk_u60(*n)],
),
Num(desugared::Num::U120(_)) => todo!(),
Num(kind_tree::Number::U120(_)) => todo!(),
Binary(operator, left, right) => mk_quoted_ctr(
eval_ctr(quote, TermTag::Binary),
vec![

View File

@ -185,7 +185,7 @@ pub fn run_cli(config: Cli) {
}
Command::Eval { file } => {
compile_in_session(render_config, root, file.clone(), &mut |session| {
driver::erase_book(session, &PathBuf::from(file.clone()))
driver::erase_book(session, &PathBuf::from(file.clone()), &["Main".to_string()])
})
.map(|res| {
println!("{}", driver::eval_in_checker(&res));

View File

@ -52,13 +52,13 @@ pub fn to_book(session: &mut Session, path: &PathBuf) -> Option<concrete::Book>
Some(concrete_book)
}
pub fn erase_book(session: &mut Session, path: &PathBuf) -> Option<desugared::Book> {
pub fn erase_book(session: &mut Session, path: &PathBuf, entrypoint: &[String]) -> Option<desugared::Book> {
let concrete_book = to_book(session, path)?;
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
erasure::erase_book(
&desugared_book,
session.diagnostic_sender.clone(),
HashSet::from_iter(vec!["Main".to_string()]),
HashSet::from_iter(entrypoint.to_owned()),
)
}
@ -79,7 +79,7 @@ pub fn check_erasure_book(session: &mut Session, path: &PathBuf) -> Option<desug
}
pub fn compile_book_to_hvm(session: &mut Session, path: &PathBuf) -> Option<backend::File> {
erase_book(session, path).map(kind_target_hvm::compile_book)
erase_book(session, path, &["Main".to_string()]).map(kind_target_hvm::compile_book)
}
pub fn execute_file(file: &backend::File) -> Box<backend::Term> {

View File

@ -6,7 +6,6 @@
use kind_pass::expand::uses::expand_uses;
use std::collections::HashSet;
use std::fs;
use std::os::linux::raw;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use strsim::jaro;

View File

@ -9,6 +9,7 @@ use crate::lexer::tokens::Token;
#[derive(Debug, Clone)]
pub enum EncodeSequence {
Hexa,
Decimal,
Octal,
Binary,
Unicode,
@ -30,11 +31,13 @@ pub enum SyntaxError {
UnusedDocString(Range),
CannotUseUse(Range),
ImportsCannotHaveAlias(Range),
InvalidNumberType(String, Range),
}
fn encode_name(encode: EncodeSequence) -> &'static str {
match encode {
EncodeSequence::Hexa => "hexadecimal",
EncodeSequence::Decimal => "decimal",
EncodeSequence::Octal => "octal",
EncodeSequence::Binary => "binary",
EncodeSequence::Unicode => "unicode",
@ -254,7 +257,7 @@ impl From<SyntaxError> for DiagnosticFrame {
}],
},
SyntaxError::CannotUseUse(range) => DiagnosticFrame {
code: 14,
code: 15,
severity: Severity::Error,
title: "Can only use the 'use' statement in the beggining of the file".to_string(),
subtitles: vec![],
@ -268,7 +271,7 @@ impl From<SyntaxError> for DiagnosticFrame {
}],
},
SyntaxError::ImportsCannotHaveAlias(range) => DiagnosticFrame {
code: 14,
code: 16,
severity: Severity::Error,
title: "The upper cased name cannot have an alias".to_string(),
subtitles: vec![],
@ -281,6 +284,20 @@ impl From<SyntaxError> for DiagnosticFrame {
main: true,
}],
},
SyntaxError::InvalidNumberType(type_, range) => DiagnosticFrame {
code: 17,
severity: Severity::Error,
title: format!("The {} number type is invalid", type_),
subtitles: vec![],
hints: vec![],
positions: vec![Marker {
position: range,
color: Color::Fst,
text: "Here!".to_string(),
no_code: false,
main: true,
}],
},
}
}
}

View File

@ -2,7 +2,7 @@ use kind_span::{Locatable, Range};
use kind_tree::concrete::expr::*;
use kind_tree::concrete::pat::PatIdent;
use kind_tree::symbol::{Ident, QualifiedIdent};
use kind_tree::Operator;
use kind_tree::{Operator, Number, NumType};
use crate::errors::SyntaxError;
use crate::lexer::tokens::Token;
@ -214,7 +214,8 @@ impl<'a> Parser<'a> {
let id = self.parse_upper_id()?;
let data = match id.to_string().as_str() {
"Type" => ExprKind::Lit(Literal::Type),
"U60" => ExprKind::Lit(Literal::U60),
"U60" => ExprKind::Lit(Literal::NumType(NumType::U60)),
"U120" => ExprKind::Lit(Literal::NumType(NumType::U120)),
_ => ExprKind::Constr(id.clone(), vec![]),
};
Ok(Box::new(Expr {
@ -228,7 +229,8 @@ impl<'a> Parser<'a> {
let mut range = id.range;
let data = match id.to_string().as_str() {
"Type" => ExprKind::Lit(Literal::Type),
"U60" => ExprKind::Lit(Literal::U60),
"U60" => ExprKind::Lit(Literal::NumType(NumType::U60)),
"U120" => ExprKind::Lit(Literal::NumType(NumType::U120)),
_ => {
let (range_end, spine) = self.parse_call_tail(id.range, multiline)?;
range = range_end;
@ -238,12 +240,21 @@ impl<'a> Parser<'a> {
Ok(Box::new(Expr { range, data }))
}
fn parse_num(&mut self, num: u64) -> Result<Box<Expr>, SyntaxError> {
fn parse_num60(&mut self, num: u64) -> Result<Box<Expr>, SyntaxError> {
let range = self.range();
self.advance();
Ok(Box::new(Expr {
range,
data: ExprKind::Lit(Literal::Number(num)),
data: ExprKind::Lit(Literal::Number(Number::U60(num))),
}))
}
fn parse_num120(&mut self, num: u128) -> Result<Box<Expr>, SyntaxError> {
let range = self.range();
self.advance();
Ok(Box::new(Expr {
range,
data: ExprKind::Lit(Literal::Number(Number::U120(num))),
}))
}
@ -367,7 +378,7 @@ impl<'a> Parser<'a> {
pub fn parse_num_lit(&mut self) -> Result<usize, SyntaxError> {
self.ignore_docs();
match self.get().clone() {
Token::Num(num) => {
Token::Num60(num) => {
self.advance();
Ok(num as usize)
}
@ -380,7 +391,8 @@ impl<'a> Parser<'a> {
match self.get().clone() {
Token::UpperId(_, _) => self.parse_single_upper(),
Token::LowerId(_) => self.parse_var(),
Token::Num(num) => self.parse_num(num),
Token::Num60(num) => self.parse_num60(num),
Token::Num120(num) => self.parse_num120(num),
Token::Char(chr) => self.parse_char(chr),
Token::Str(str) => self.parse_str(str),
Token::Help(str) => self.parse_help(str),

View File

@ -54,30 +54,49 @@ impl<'a> Lexer<'a> {
}
}
/// Lex a base-10 digit.
fn lex_digit(&mut self, start: usize) -> (Token, Range) {
let num = self.accumulate_while(&|x| x.is_ascii_digit() || x == '_');
(
Token::Num(num.replace('_', "").parse::<u64>().unwrap()),
self.mk_range(start),
)
}
/// Lexes a number of base @base@ removing the first
/// character that indicates the encoding
fn lex_base(&mut self, start: usize, base: u32, err: EncodeSequence) -> (Token, Range) {
self.next_char();
/// Lexes a number of base @base@, figuring out it's type
/// Lexes 0 if not at a digit position
fn lex_num_and_type_with_base(&mut self, num_start: usize, base: u32, err: EncodeSequence) -> (Token, Range) {
let num = self.accumulate_while(&|x| x.is_digit(base) || x == '_');
if let Ok(res) = u64::from_str_radix(&num.replace('_', ""), base) {
(Token::Num(res), self.mk_range(start))
} else {
(
Token::Error(Box::new(SyntaxError::InvalidNumberRepresentation(
err,
self.mk_range(start),
))),
self.mk_range(start),
)
let num = if num.is_empty() { "0" } else { num };
let num = num.to_string();
let type_start = self.span();
let make_num_err = |x: &Self| (
Token::Error(Box::new(SyntaxError::InvalidNumberRepresentation(err, x.mk_range(num_start)))),
x.mk_range(num_start),
);
match self.peekable.peek() {
Some('U' | 'u') => {
self.next_char();
let type_ = self.accumulate_while(&|x| x.is_ascii_digit());
match type_ {
"60" => {
if let Ok(res) = u64::from_str_radix(&num.replace('_', ""), base) {
(Token::Num60(res), self.mk_range(num_start))
} else {
make_num_err(self)
}
}
"120" => {
if let Ok(res) = u128::from_str_radix(&num.replace('_', ""), base) {
(Token::Num120(res), self.mk_range(num_start))
} else {
make_num_err(self)
}
}
_ => (
Token::Error(Box::new(SyntaxError::InvalidNumberType(format!("u{}", type_), self.mk_range(type_start)))),
self.mk_range(type_start),
),
}
},
Some(_) | None => {
if let Ok(res) = u64::from_str_radix(&num.replace('_', ""), base) {
(Token::Num60(res), self.mk_range(num_start))
} else {
make_num_err(self)
}
}
}
}
@ -89,16 +108,22 @@ impl<'a> Lexer<'a> {
Some('0') => {
self.next_char();
match self.peekable.peek() {
Some('x') => self.lex_base(start, 16, EncodeSequence::Hexa),
Some('o') => self.lex_base(start, 8, EncodeSequence::Octal),
Some('b') => self.lex_base(start, 2, EncodeSequence::Binary),
Some('0'..='9') => self.lex_digit(start),
Some(_) => (Token::Num(0), self.mk_range(start)),
None => (Token::Num(0), self.mk_range(start)),
Some('x' | 'X') => {
self.next_char();
self.lex_num_and_type_with_base(start, 16, EncodeSequence::Hexa)
}
Some('o' | 'O') => {
self.next_char();
self.lex_num_and_type_with_base(start, 8, EncodeSequence::Octal)
}
Some('b' | 'B') => {
self.next_char();
self.lex_num_and_type_with_base(start, 2, EncodeSequence::Binary)
}
Some('0'..='9' | _) | None => self.lex_num_and_type_with_base(start, 10, EncodeSequence::Decimal),
}
}
Some('0'..='9') => self.lex_digit(start),
Some(_) => (Token::Num(0), self.mk_range(start)),
Some('0'..='9' | _) => self.lex_num_and_type_with_base(start, 10, EncodeSequence::Decimal),
}
}

View File

@ -46,7 +46,8 @@ pub enum Token {
// Literals
Char(char),
Str(String),
Num(u64),
Num60(u64),
Num120(u128),
Float(u64, u64),
Hole,
@ -101,8 +102,12 @@ impl Token {
matches!(self, Token::Str(_))
}
pub fn is_num(&self) -> bool {
matches!(self, Token::Num(_))
pub fn is_num60(&self) -> bool {
matches!(self, Token::Num60(_))
}
pub fn is_num120(&self) -> bool {
matches!(self, Token::Num120(_))
}
pub fn is_eof(&self) -> bool {
@ -148,7 +153,8 @@ impl fmt::Display for Token {
Token::As => write!(f, "as"),
Token::Char(c) => write!(f, "'{}'", c),
Token::Str(s) => write!(f, "\"{}\"", s),
Token::Num(n) => write!(f, "{}", n),
Token::Num60(n) => write!(f, "{}", n),
Token::Num120(n) => write!(f, "{}u120", n),
Token::Float(start, end) => write!(f, "{}.{}", start, end),
Token::Hole => write!(f, "-"),
Token::Plus => write!(f, "+"),

View File

@ -25,12 +25,21 @@ impl<'a> Parser<'a> {
}))
}
pub fn parse_pat_num(&mut self) -> Result<Box<Pat>, SyntaxError> {
pub fn parse_pat_num60(&mut self) -> Result<Box<Pat>, SyntaxError> {
let start = self.range();
let num = eat_single!(self, Token::Num(n) => *n)?;
let num = eat_single!(self, Token::Num60(n) => *n)?;
Ok(Box::new(Pat {
range: start,
data: PatKind::Num(num),
data: PatKind::Num(kind_tree::Number::U60(num)),
}))
}
pub fn parse_pat_num120(&mut self) -> Result<Box<Pat>, SyntaxError> {
let start = self.range();
let num = eat_single!(self, Token::Num120(n) => *n)?;
Ok(Box::new(Pat {
range: start,
data: PatKind::Num(kind_tree::Number::U120(num)),
}))
}
@ -122,8 +131,10 @@ impl<'a> Parser<'a> {
self.parse_pat_constructor()
} else if self.get().is_str() {
self.parse_pat_str()
} else if self.get().is_num() {
self.parse_pat_num()
} else if self.get().is_num60() {
self.parse_pat_num60()
} else if self.get().is_num120() {
self.parse_pat_num120()
} else if self.check_actual(Token::LPar) {
self.parse_pat_group()
} else if self.get().is_lower_id() {

View File

@ -13,7 +13,7 @@ impl<'a> Parser<'a> {
let ident = self.parse_id()?;
Ok(AttributeStyle::Ident(range, ident))
}
Token::Num(num) => {
Token::Num60(num) => {
let range = self.range();
self.advance();
Ok(AttributeStyle::Number(range, num))

View File

@ -16,9 +16,10 @@ impl<'a> DesugarState<'a> {
match literal {
Literal::Type => desugared::Expr::typ(range),
Literal::Help(name) => desugared::Expr::hlp(range, name.clone()),
Literal::U60 => desugared::Expr::u60(range),
// TODO: Add u120 literals
Literal::Number(num) => desugared::Expr::num60(range, *num),
Literal::NumType(kind_tree::NumType::U60) => desugared::Expr::u60(range),
Literal::NumType(kind_tree::NumType::U120) => desugared::Expr::u120(range),
Literal::Number(kind_tree::Number::U60(num)) => desugared::Expr::num60(range, *num),
Literal::Number(kind_tree::Number::U120(num)) => desugared::Expr::num120(range, *num),
Literal::String(string) => desugared::Expr::str(range, string.to_owned()),
Literal::Char(_) => todo!(),
}

View File

@ -253,8 +253,9 @@ impl<'a> DesugarState<'a> {
}
pub fn desugar_pat(&mut self, pat: &concrete::pat::Pat) -> Box<desugared::Expr> {
use concrete::pat::PatKind;
match &pat.data {
concrete::pat::PatKind::App(head, spine) => {
PatKind::App(head, spine) => {
// TODO: Fix lol
let entry = self
.old_book
@ -297,16 +298,17 @@ impl<'a> DesugarState<'a> {
}
desugared::Expr::ctr(pat.range, head.clone(), new_spine)
}
concrete::pat::PatKind::Hole => {
PatKind::Hole => {
let name = self.gen_name(pat.range);
desugared::Expr::var(name)
}
concrete::pat::PatKind::Var(ident) => desugared::Expr::var(ident.0.clone()),
PatKind::Var(ident) => desugared::Expr::var(ident.0.clone()),
// TODO: Add u120 pattern literals
concrete::pat::PatKind::Num(n) => desugared::Expr::num60(pat.range, *n),
concrete::pat::PatKind::Pair(fst, snd) => self.desugar_pair_pat(pat.range, fst, snd),
concrete::pat::PatKind::List(ls) => self.desugar_list_pat(pat.range, ls),
concrete::pat::PatKind::Str(string) => {
PatKind::Num(kind_tree::Number::U60(n)) => desugared::Expr::num60(pat.range, *n),
PatKind::Num(kind_tree::Number::U120(n)) => desugared::Expr::num120(pat.range, *n),
PatKind::Pair(fst, snd) => self.desugar_pair_pat(pat.range, fst, snd),
PatKind::List(ls) => self.desugar_list_pat(pat.range, ls),
PatKind::Str(string) => {
desugared::Expr::str(pat.range, string.to_owned())
}
}

View File

@ -30,20 +30,19 @@ pub fn compile_term(expr: &desugared::Expr) -> Box<Term> {
}),
Ann(left, _) => compile_term(left),
Sub(_, _, _, expr) => compile_term(expr),
Num(desugared::Num::U60(numb)) => Box::new(Term::Num { numb: *numb }),
Num(_) => todo!(),
Num(kind_tree::Number::U60(numb)) => Box::new(Term::Num { numb: *numb }),
Num(kind_tree::Number::U120(numb)) => {
let hi = Box::new(Term::Num { numb: (numb >> 60) as u64});
let lo = Box::new(Term::Num { numb: (numb & 0xFFFFFFFFFFFFFFF) as u64});
Box::new(Term::Ctr { name: String::from("U120.new"), args: vec![hi, lo] })
}
Binary(op, l, r) => Box::new(Term::Ctr {
name: op.to_string(),
args: vec![compile_term(l), compile_term(r)],
}),
Hole(_) => unreachable!("Internal Error: 'Hole' cannot be a relevant term"),
Typ => unreachable!("Internal Error: 'Typ' cannot be a relevant term"),
NumType(desugared::NumType::U60) => {
unreachable!("Internal Error: 'U60' cannot be a relevant term")
}
NumType(desugared::NumType::U120) => {
unreachable!("Internal Error: 'U120' cannot be a relevant term")
}
NumType(typ) => unreachable!("Internal Error: '{:?}' cannot be a relevant term", typ),
All(_, _, _) => unreachable!("Internal Error: 'All' cannot be a relevant term"),
Str(_) => unreachable!("Internal Error: 'Str' cannot be a relevant term"),
Hlp(_) => unreachable!("Internal Error: 'Hlp' cannot be a relevant term"),

View File

@ -87,11 +87,11 @@ pub enum Literal {
/// and the goal (e.g. ?)
Help(Ident),
/// The type of 60 bits numberss (e.g. 2 : U60)
U60,
NumType(crate::NumType),
// Char literal
Char(char),
/// A number literal of 60 bits (e.g 32132)
Number(u64),
Number(crate::Number),
// A String literal
String(String),
}
@ -266,9 +266,11 @@ impl Display for Literal {
match self {
Literal::Help(s) => write!(f, "?{}", s),
Literal::Type => write!(f, "Type"),
Literal::U60 => write!(f, "U60"),
Literal::NumType(crate::NumType::U60) => write!(f, "U60"),
Literal::NumType(crate::NumType::U120) => write!(f, "U120"),
Literal::Char(c) => write!(f, "'{}'", c),
Literal::Number(numb) => write!(f, "{}", numb),
Literal::Number(crate::Number::U60(numb)) => write!(f, "{}", numb),
Literal::Number(crate::Number::U120(numb)) => write!(f, "{}u120", numb),
Literal::String(str) => {
write!(f, "{:?}", str)
}

View File

@ -19,8 +19,8 @@ pub enum PatKind {
Var(PatIdent),
/// Application of a constructor
App(QualifiedIdent, Vec<Box<Pat>>),
/// Hole
Num(u64),
/// Number
Num(crate::Number),
/// Pair
Pair(Box<Pat>, Box<Pat>),
/// List
@ -58,7 +58,8 @@ impl Display for Pat {
.join(" ")
),
Str(str) => write!(f, "\"{}\"", str),
Num(num) => write!(f, "{}", num),
Num(crate::Number::U60(num)) => write!(f, "{}", num),
Num(crate::Number::U120(num)) => write!(f, "{}u120", num),
Pair(fst, snd) => write!(f, "({}, {})", fst, snd),
Hole => write!(f, "_"),
}

View File

@ -46,9 +46,9 @@ pub enum ExprKind {
/// Type Literal
Typ,
/// Primitive numeric types
NumType(NumType),
NumType(crate::NumType),
/// Primitive numeric values
Num(Num),
Num(crate::Number),
/// Very special constructor :)
Str(String),
/// Binary operation (e.g. 2 + 3)
@ -167,28 +167,28 @@ impl Expr {
pub fn u60(range: Range) -> Box<Expr> {
Box::new(Expr {
span: Span::Locatable(range),
data: ExprKind::NumType(NumType::U60),
data: ExprKind::NumType(crate::NumType::U60),
})
}
pub fn u120(range: Range) -> Box<Expr> {
Box::new(Expr {
span: Span::Locatable(range),
data: ExprKind::NumType(NumType::U120),
data: ExprKind::NumType(crate::NumType::U120),
})
}
pub fn num60(range: Range, num: u64) -> Box<Expr> {
Box::new(Expr {
span: Span::Locatable(range),
data: ExprKind::Num(Num::U60(num)),
data: ExprKind::Num(crate::Number::U60(num)),
})
}
pub fn num120(range: Range, num: u128) -> Box<Expr> {
Box::new(Expr {
span: Span::Locatable(range),
data: ExprKind::Num(Num::U120(num)),
data: ExprKind::Num(crate::Number::U120(num)),
})
}
@ -228,18 +228,6 @@ impl Expr {
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Num {
U60(u64),
U120(u128),
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum NumType {
U60,
U120,
}
/// An argument is a 'binding' of a name to a type
/// it has some other options like
/// eras: that express the erasure of this type when
@ -330,11 +318,11 @@ impl Display for Expr {
use ExprKind::*;
match &self.data {
Typ => write!(f, "Type"),
NumType(self::NumType::U60) => write!(f, "U60"),
NumType(self::NumType::U120) => write!(f, "U120"),
NumType(crate::NumType::U60) => write!(f, "U60"),
NumType(crate::NumType::U120) => write!(f, "U120"),
Str(n) => write!(f, "\"{}\"", n),
Num(self::Num::U60(n)) => write!(f, "{}", n),
Num(self::Num::U120(n)) => write!(f, "{}u120", n),
Num(crate::Number::U60(n)) => write!(f, "{}", n),
Num(crate::Number::U120(n)) => write!(f, "{}u120", n),
All(_, _, _) => write!(f, "({})", self.traverse_pi_types()),
Var(name) => write!(f, "{}", name),
Lambda(binder, body, false) => write!(f, "({} => {})", binder, body),

View File

@ -38,3 +38,16 @@ pub enum Operator {
Gtn,
Neq,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Number {
U60(u64),
U120(u128),
// TODO: F60
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum NumType {
U60,
U120,
}