supporting ascii literals
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
dc96c8b10a
commit
00f6729d31
|
@ -121,10 +121,12 @@ main := fn(): uint {
|
||||||
decimal := 255
|
decimal := 255
|
||||||
octal := 0o377
|
octal := 0o377
|
||||||
binary := 0b11111111
|
binary := 0b11111111
|
||||||
|
ascii := '\n'
|
||||||
|
|
||||||
if hex == decimal & octal == decimal & binary == decimal {
|
if hex == decimal & octal == decimal & binary == decimal {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -314,6 +314,7 @@ impl<'a> Formatter<'a> {
|
||||||
}
|
}
|
||||||
Expr::Slf { .. } => f.write_str("Self"),
|
Expr::Slf { .. } => f.write_str("Self"),
|
||||||
Expr::String { literal, .. } => f.write_str(literal),
|
Expr::String { literal, .. } => f.write_str(literal),
|
||||||
|
Expr::Char { literal, .. } => f.write_str(literal),
|
||||||
Expr::Comment { literal, .. } => f.write_str(literal),
|
Expr::Comment { literal, .. } => f.write_str(literal),
|
||||||
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
|
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
|
||||||
Expr::Embed { path, .. } => write!(f, "@embed(\"{path}\")"),
|
Expr::Embed { path, .. } => write!(f, "@embed(\"{path}\")"),
|
||||||
|
|
|
@ -306,7 +306,7 @@ fn endoce_string(
|
||||||
literal: &str,
|
literal: &str,
|
||||||
str: &mut Vec<u8>,
|
str: &mut Vec<u8>,
|
||||||
report: impl Fn(&core::str::Bytes, &str),
|
report: impl Fn(&core::str::Bytes, &str),
|
||||||
) -> Option<()> {
|
) -> Option<usize> {
|
||||||
let report = |bytes: &core::str::Bytes, msg: &_| {
|
let report = |bytes: &core::str::Bytes, msg: &_| {
|
||||||
report(bytes, msg);
|
report(bytes, msg);
|
||||||
None::<u8>
|
None::<u8>
|
||||||
|
@ -332,7 +332,9 @@ fn endoce_string(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = literal.bytes();
|
let mut bytes = literal.bytes();
|
||||||
|
let mut char_len = 0;
|
||||||
while let Some(b) = bytes.next() {
|
while let Some(b) = bytes.next() {
|
||||||
|
char_len += 1;
|
||||||
if b != b'\\' {
|
if b != b'\\' {
|
||||||
str.push(b);
|
str.push(b);
|
||||||
continue;
|
continue;
|
||||||
|
@ -354,11 +356,7 @@ fn endoce_string(
|
||||||
str.push(b);
|
str.push(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if str.last() != Some(&0) {
|
Some(char_len)
|
||||||
report(&bytes, "string literal must end with null byte (for now)");
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn quad_sort<T>(mut slice: &mut [T], mut cmp: impl FnMut(&T, &T) -> core::cmp::Ordering) {
|
pub fn quad_sort<T>(mut slice: &mut [T], mut cmp: impl FnMut(&T, &T) -> core::cmp::Ordering) {
|
||||||
|
|
|
@ -356,6 +356,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
T::Idk => E::Idk { pos },
|
T::Idk => E::Idk { pos },
|
||||||
T::Die => E::Die { pos },
|
T::Die => E::Die { pos },
|
||||||
T::DQuote => E::String { pos, literal: self.tok_str(token) },
|
T::DQuote => E::String { pos, literal: self.tok_str(token) },
|
||||||
|
T::Quote => E::Char { pos, literal: self.tok_str(token) },
|
||||||
T::Packed => {
|
T::Packed => {
|
||||||
self.packed = true;
|
self.packed = true;
|
||||||
let expr = self.unit_expr()?;
|
let expr = self.unit_expr()?;
|
||||||
|
@ -896,6 +897,11 @@ generate_expr! {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
literal: &'a str,
|
literal: &'a str,
|
||||||
},
|
},
|
||||||
|
/// `'\'([^']|\\\')\''`
|
||||||
|
Char {
|
||||||
|
pos: Pos,
|
||||||
|
literal: &'a str,
|
||||||
|
},
|
||||||
/// `'//[^\n]' | '/*' { '([^/*]|*/)*' | Comment } '*/'
|
/// `'//[^\n]' | '/*' { '([^/*]|*/)*' | Comment } '*/'
|
||||||
Comment {
|
Comment {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
|
|
|
@ -2975,7 +2975,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
Expr::Ident { id, pos, .. } => self.find_type_as_value(pos, self.ci.parent, id, ctx),
|
Expr::Ident { id, pos, .. } => self.find_type_as_value(pos, self.ci.parent, id, ctx),
|
||||||
Expr::Comment { .. } => Some(Value::VOID),
|
Expr::Comment { .. } => Some(Value::VOID),
|
||||||
Expr::String { pos, literal } => {
|
Expr::Char { pos, literal } | Expr::String { pos, literal } => {
|
||||||
let literal = &literal[1..literal.len() - 1];
|
let literal = &literal[1..literal.len() - 1];
|
||||||
let mut data = core::mem::take(&mut self.pool.lit_buf);
|
let mut data = core::mem::take(&mut self.pool.lit_buf);
|
||||||
debug_assert!(data.is_empty());
|
debug_assert!(data.is_empty());
|
||||||
|
@ -2984,27 +2984,51 @@ impl<'a> Codegen<'a> {
|
||||||
self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message);
|
self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::endoce_string(literal, &mut data, report).unwrap();
|
let char_count = crate::endoce_string(literal, &mut data, report).unwrap();
|
||||||
|
|
||||||
let ty = self.tys.make_ptr(ty::Id::U8);
|
if matches!(expr, Expr::Char { .. }) {
|
||||||
let global = self
|
if char_count != 1 {
|
||||||
.tys
|
return self.error(
|
||||||
.strings
|
pos,
|
||||||
.get_or_insert(&data, &mut self.tys.ins.globals, |globals| {
|
fa!("character literal can only contain one character, \
|
||||||
StringRef(globals.push(GlobalData {
|
but you supplied {char_count}"),
|
||||||
data: data.clone(),
|
);
|
||||||
ty,
|
}
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.0;
|
|
||||||
let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]);
|
|
||||||
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
|
|
||||||
|
|
||||||
data.clear();
|
let value = match data.as_slice() {
|
||||||
self.pool.lit_buf = data;
|
&[v] => v as i64,
|
||||||
|
_ => return self.error(pos, "TODO: support utf-8 characters"),
|
||||||
|
};
|
||||||
|
|
||||||
Some(Value::new(global).ty(ty))
|
data.clear();
|
||||||
|
self.pool.lit_buf = data;
|
||||||
|
|
||||||
|
self.gen_inferred_const(ctx, ty::Id::U8, value, ty::Id::is_integer)
|
||||||
|
} else {
|
||||||
|
if data.last() != Some(&0) {
|
||||||
|
self.error(pos, "string literal must end with null byte (for now)");
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = self.tys.make_ptr(ty::Id::U8);
|
||||||
|
let global = self
|
||||||
|
.tys
|
||||||
|
.strings
|
||||||
|
.get_or_insert(&data, &mut self.tys.ins.globals, |globals| {
|
||||||
|
StringRef(globals.push(GlobalData {
|
||||||
|
data: data.clone(),
|
||||||
|
ty,
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.0;
|
||||||
|
let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]);
|
||||||
|
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
|
||||||
|
|
||||||
|
data.clear();
|
||||||
|
self.pool.lit_buf = data;
|
||||||
|
|
||||||
|
Some(Value::new(global).ty(ty))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Defer { pos, value } => {
|
Expr::Defer { pos, value } => {
|
||||||
self.ci.defers.push((pos, ExprRef::new(value)));
|
self.ci.defers.push((pos, ExprRef::new(value)));
|
||||||
|
|
Loading…
Reference in a new issue