nac3ast/parser/core: use i128 for u64 constants

escape-analysis
ychenfo 2022-03-08 02:30:04 +08:00
parent 9f6c7b3359
commit f7e62ab5b7
7 changed files with 80 additions and 120 deletions

View File

@ -4,7 +4,7 @@ pub enum Constant {
Bool(bool), Bool(bool),
Str(String), Str(String),
Bytes(Vec<u8>), Bytes(Vec<u8>),
Int(Option<i64>), Int(i128),
Tuple(Vec<Constant>), Tuple(Vec<Constant>),
Float(f64), Float(f64),
Complex { real: f64, imag: f64 }, Complex { real: f64, imag: f64 },
@ -28,12 +28,12 @@ impl From<bool> for Constant {
} }
impl From<i32> for Constant { impl From<i32> for Constant {
fn from(i: i32) -> Constant { fn from(i: i32) -> Constant {
Self::Int(Some(i as i64)) Self::Int(i as i128)
} }
} }
impl From<i64> for Constant { impl From<i64> for Constant {
fn from(i: i64) -> Constant { fn from(i: i64) -> Constant {
Self::Int(Some(i)) Self::Int(i as i128)
} }
} }

View File

@ -153,7 +153,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let ty = self.ctx.bool_type(); let ty = self.ctx.bool_type();
ty.const_int(if *v { 1 } else { 0 }, false).into() ty.const_int(if *v { 1 } else { 0 }, false).into()
} }
Constant::Int(Some(val)) => { Constant::Int(val) => {
let ty = if self.unifier.unioned(ty, self.primitives.int32) let ty = if self.unifier.unioned(ty, self.primitives.int32)
|| self.unifier.unioned(ty, self.primitives.uint32) || self.unifier.unioned(ty, self.primitives.uint32)
{ {
@ -1315,7 +1315,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
.into_struct_value(); .into_struct_value();
let index: u32 = let index: u32 =
if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node { if let ExprKind::Constant { value: ast::Constant::Int(v), .. } = &slice.node {
v.unwrap().try_into().unwrap() (*v).try_into().unwrap()
} else { } else {
unreachable!("tuple subscript must be const int after type check"); unreachable!("tuple subscript must be const int after type check");
}; };

View File

@ -463,16 +463,13 @@ pub fn parse_parameter_default_value(
) -> Result<SymbolValue, String> { ) -> Result<SymbolValue, String> {
fn handle_constant(val: &Constant, loc: &Location) -> Result<SymbolValue, String> { fn handle_constant(val: &Constant, loc: &Location) -> Result<SymbolValue, String> {
match val { match val {
Constant::Int(v) => match v { Constant::Int(v) => {
Some(v) => { if let Ok(v) = (*v).try_into() {
if let Ok(v) = (*v).try_into() { Ok(SymbolValue::I32(v))
Ok(SymbolValue::I32(v)) } else {
} else { Err(format!("integer value out of range at {}", loc))
Err(format!("integer value out of range at {}", loc))
}
} }
None => Err(format!("integer value out of range at {}", loc)), }
},
Constant::Float(v) => Ok(SymbolValue::Double(*v)), Constant::Float(v) => Ok(SymbolValue::Double(*v)),
Constant::Bool(v) => Ok(SymbolValue::Bool(*v)), Constant::Bool(v) => Ok(SymbolValue::Bool(*v)),
Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( Constant::Tuple(tuple) => Ok(SymbolValue::Tuple(
@ -483,62 +480,39 @@ pub fn parse_parameter_default_value(
} }
match &default.node { match &default.node {
ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location),
ast::ExprKind::Call { func, args, .. } if { ast::ExprKind::Call { func, args, .. } if args.len() == 1 => {
match &func.node { match &func.node {
ast::ExprKind::Name { id, .. } => *id == "int64".into(), ast::ExprKind::Name { id, .. } if *id == "int64".into() => match &args[0].node {
_ => false, ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
} let v: Result<i64, _> = (*v).try_into();
} => { match v {
if args.len() == 1 { Ok(v) => Ok(SymbolValue::I64(v)),
match &args[0].node { _ => Err(format!("default param value out of range at {}", default.location)),
ast::ExprKind::Constant { value: Constant::Int(Some(v)), .. } => }
Ok(SymbolValue::I64(*v)), }
_ => Err(format!("only allow constant integer here at {}", default.location)) _ => Err(format!("only allow constant integer here at {}", default.location))
} }
} else { ast::ExprKind::Name { id, .. } if *id == "uint32".into() => match &args[0].node {
Err(format!("only allow constant integer here at {}", default.location)) ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
}
}
ast::ExprKind::Call { func, args, .. } if {
match &func.node {
ast::ExprKind::Name { id, .. } => *id == "uint32".into(),
_ => false,
}
} => {
if args.len() == 1 {
match &args[0].node {
ast::ExprKind::Constant { value: Constant::Int(Some(v)), .. } => {
let v: Result<u32, _> = (*v).try_into(); let v: Result<u32, _> = (*v).try_into();
match v { match v {
Ok(v) => Ok(SymbolValue::U32(v)), Ok(v) => Ok(SymbolValue::U32(v)),
_ => Err(format!("default param value out of range at {}", default.location)) _ => Err(format!("default param value out of range at {}", default.location)),
} }
} }
_ => Err(format!("only allow constant integer here at {}", default.location)) _ => Err(format!("only allow constant integer here at {}", default.location))
} }
} else { ast::ExprKind::Name { id, .. } if *id == "uint64".into() => match &args[0].node {
Err(format!("only allow constant integer here at {}", default.location)) ast::ExprKind::Constant { value: Constant::Int(v), .. } => {
}
}
ast::ExprKind::Call { func, args, .. } if {
match &func.node {
ast::ExprKind::Name { id, .. } => *id == "uint64".into(),
_ => false,
}
} => {
if args.len() == 1 {
match &args[0].node {
ast::ExprKind::Constant { value: Constant::Int(Some(v)), .. } => {
let v: Result<u64, _> = (*v).try_into(); let v: Result<u64, _> = (*v).try_into();
match v { match v {
Ok(v) => Ok(SymbolValue::U64(v)), Ok(v) => Ok(SymbolValue::U64(v)),
_ => Err(format!("default param value out of range at {}", default.location)) _ => Err(format!("default param value out of range at {}", default.location)),
} }
} }
_ => Err(format!("only allow constant integer here at {}", default.location)) _ => Err(format!("only allow constant integer here at {}", default.location))
} }
} else { _ => Err(format!("unsupported default parameter at {}", default.location)),
Err(format!("only allow constant integer here at {}", default.location))
} }
} }
ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts

View File

@ -781,21 +781,19 @@ impl<'a> Inferencer<'a> {
&args[0].node &args[0].node
{ {
let custom = Some(self.primitives.int64); let custom = Some(self.primitives.int64);
match val { let v: Result<i64, _> = (*val).try_into();
Some(val) if { if v.is_ok() {
let v: Result<i64, _> = (*val).try_into(); return Ok(Located {
v.is_ok() location: args[0].location,
} => {}, custom,
_ => return report_error("Integer out of bound", args[0].location) node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} else {
return report_error("Integer out of bound", args[0].location)
} }
return Ok(Located {
location: args[0].location,
custom,
node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} }
} }
if id == "uint32".into() && args.len() == 1 { if id == "uint32".into() && args.len() == 1 {
@ -803,21 +801,19 @@ impl<'a> Inferencer<'a> {
&args[0].node &args[0].node
{ {
let custom = Some(self.primitives.uint32); let custom = Some(self.primitives.uint32);
match val { let v: Result<u32, _> = (*val).try_into();
Some(val) if { if v.is_ok() {
let v: Result<u32, _> = (*val).try_into(); return Ok(Located {
v.is_ok() location: args[0].location,
} => {}, custom,
_ => return report_error("Integer out of bound", args[0].location) node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} else {
return report_error("Integer out of bound", args[0].location)
} }
return Ok(Located {
location: args[0].location,
custom,
node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} }
} }
if id == "uint64".into() && args.len() == 1 { if id == "uint64".into() && args.len() == 1 {
@ -825,21 +821,19 @@ impl<'a> Inferencer<'a> {
&args[0].node &args[0].node
{ {
let custom = Some(self.primitives.uint64); let custom = Some(self.primitives.uint64);
match val { let v: Result<u64, _> = (*val).try_into();
Some(val) if { if v.is_ok() {
let v: Result<u64, _> = (*val).try_into(); return Ok(Located {
v.is_ok() location: args[0].location,
} => {}, custom,
_ => return report_error("Integer out of bound", args[0].location) node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} else {
return report_error("Integer out of bound", args[0].location)
} }
return Ok(Located {
location: args[0].location,
custom,
node: ExprKind::Constant {
value: ast::Constant::Int(*val),
kind: kind.clone(),
},
});
} }
} }
Located { location: func_location, custom, node: ExprKind::Name { id, ctx } } Located { location: func_location, custom, node: ExprKind::Name { id, ctx } }
@ -923,17 +917,12 @@ impl<'a> Inferencer<'a> {
match constant { match constant {
ast::Constant::Bool(_) => Ok(self.primitives.bool), ast::Constant::Bool(_) => Ok(self.primitives.bool),
ast::Constant::Int(val) => { ast::Constant::Int(val) => {
match val { let int32: Result<i32, _> = (*val).try_into();
Some(val) => { // int64 and unsigned integers are handled separately in functions
let int32: Result<i32, _> = (*val).try_into(); if int32.is_ok() {
// int64 and unsigned integers are handled separately in functions Ok(self.primitives.int32)
if int32.is_ok() { } else {
Ok(self.primitives.int32) report_error("Integer out of bound", *loc)
} else {
report_error("Integer out of bound", *loc)
}
}
None => report_error("Integer out of bound", *loc),
} }
} }
ast::Constant::Float(_) => Ok(self.primitives.float), ast::Constant::Float(_) => Ok(self.primitives.float),
@ -1066,10 +1055,7 @@ impl<'a> Inferencer<'a> {
} }
ast::ExprKind::Constant { value: ast::Constant::Int(val), .. } => { ast::ExprKind::Constant { value: ast::Constant::Int(val), .. } => {
// the index is a constant, so value can be a sequence. // the index is a constant, so value can be a sequence.
let ind: Option<i32> = match val { let ind: Option<i32> = (*val).try_into().ok();
Some(val) => (*val).try_into().ok(),
None => None,
};
let ind = ind.ok_or_else(|| "Index must be int32".to_string())?; let ind = ind.ok_or_else(|| "Index must be int32".to_string())?;
let map = once(( let map = once((
ind.into(), ind.into(),

View File

@ -285,11 +285,11 @@ where
fn lex_number_radix(&mut self, start_pos: Location, radix: u32) -> LexResult { fn lex_number_radix(&mut self, start_pos: Location, radix: u32) -> LexResult {
let value_text = self.radix_run(radix); let value_text = self.radix_run(radix);
let end_pos = self.get_pos(); let end_pos = self.get_pos();
let value = match i64::from_str_radix(&value_text, radix) { let value = match i128::from_str_radix(&value_text, radix) {
Ok(value) => Some(value), Ok(value) => value,
Err(e) => { Err(e) => {
match e.kind() { match e.kind() {
IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => None, IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => i128::MAX,
_ => return Err(LexicalError { _ => return Err(LexicalError {
error: LexicalErrorType::OtherError(format!("{:?}", e)), error: LexicalErrorType::OtherError(format!("{:?}", e)),
location: start_pos, location: start_pos,
@ -361,9 +361,9 @@ where
let end_pos = self.get_pos(); let end_pos = self.get_pos();
// assumption: value_text contains a valid integer. // assumption: value_text contains a valid integer.
// parse should only fail because of overflow. // parse should only fail because of overflow.
let value = value_text.parse::<i64>().ok(); let value = value_text.parse::<i128>().ok();
let nonzero = match value { let nonzero = match value {
Some(value) => value != 0i64, Some(value) => value != 0i128,
None => true None => true
}; };
if start_is_zero && nonzero { if start_is_zero && nonzero {
@ -372,7 +372,7 @@ where
location: self.get_pos(), location: self.get_pos(),
}); });
} }
Ok((start_pos, Tok::Int { value }, end_pos)) Ok((start_pos, Tok::Int { value: value.unwrap_or(i128::MAX) }, end_pos))
} }
} }
} }

View File

@ -919,7 +919,7 @@ Factor: ast::Expr = {
match (&op, &e.node) { match (&op, &e.node) {
(ast::Unaryop::USub, ast::ExprKind::Constant { value: Constant::Int(val), kind }) => { (ast::Unaryop::USub, ast::ExprKind::Constant { value: Constant::Int(val), kind }) => {
ast::ExprKind::Constant { ast::ExprKind::Constant {
value: if let Some(val) = val { Constant::Int(Some(-val)) } else { Constant::Int(None) }, value: if i128::MAX == *val { Constant::Int(*val) } else { Constant::Int(-val) },
kind: kind.clone() kind: kind.clone()
} }
} }
@ -1361,7 +1361,7 @@ extern {
"True" => lexer::Tok::True, "True" => lexer::Tok::True,
"False" => lexer::Tok::False, "False" => lexer::Tok::False,
"None" => lexer::Tok::None, "None" => lexer::Tok::None,
int => lexer::Tok::Int { value: <Option<i64>> }, int => lexer::Tok::Int { value: <i128> },
float => lexer::Tok::Float { value: <f64> }, float => lexer::Tok::Float { value: <f64> },
complex => lexer::Tok::Complex { real: <f64>, imag: <f64> }, complex => lexer::Tok::Complex { real: <f64>, imag: <f64> },
string => lexer::Tok::String { value: <String>, is_fstring: <bool> }, string => lexer::Tok::String { value: <String>, is_fstring: <bool> },

View File

@ -7,7 +7,7 @@ use crate::ast;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Tok { pub enum Tok {
Name { name: ast::StrRef }, Name { name: ast::StrRef },
Int { value: Option<i64> }, Int { value: i128 },
Float { value: f64 }, Float { value: f64 },
Complex { real: f64, imag: f64 }, Complex { real: f64, imag: f64 },
String { value: String, is_fstring: bool }, String { value: String, is_fstring: bool },
@ -112,7 +112,7 @@ impl fmt::Display for Tok {
use Tok::*; use Tok::*;
match self { match self {
Name { name } => write!(f, "'{}'", ast::get_str_from_ref(&ast::get_str_ref_lock(), *name)), Name { name } => write!(f, "'{}'", ast::get_str_from_ref(&ast::get_str_ref_lock(), *name)),
Int { value } => if let Some(value) = value { write!(f, "'{}'", value) } else { write!(f, "'#OFL#'") }, Int { value } => if *value != i128::MAX { write!(f, "'{}'", value) } else { write!(f, "'#OFL#'") },
Float { value } => write!(f, "'{}'", value), Float { value } => write!(f, "'{}'", value),
Complex { real, imag } => write!(f, "{}j{}", real, imag), Complex { real, imag } => write!(f, "{}j{}", real, imag),
String { value, is_fstring } => { String { value, is_fstring } => {