Skip to content

Commit 35da9bb

Browse files
committed
Added support for C char literals
1 parent 0d628e8 commit 35da9bb

File tree

11 files changed

+108
-61
lines changed

11 files changed

+108
-61
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ Adept 3.x will have:
3232
- New documentation generator
3333
- No more support for old alternative syntaxes
3434
- Additional fixes for previous design mistakes
35+
36+
## Thank you for sponsoring Adept ❤️
37+
38+
- Spoiledpay

src/ast/expr/integer.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ pub enum Integer {
1616
pub struct IntegerKnown {
1717
pub rigidity: IntegerRigidity,
1818
pub value: BigInt,
19-
pub sign: IntegerSign,
2019
}
2120

2221
impl IntegerKnown {
2322
pub fn make_type(&self, source: Source) -> resolved::Type {
2423
match self.rigidity {
25-
IntegerRigidity::Fixed(bits) => resolved::TypeKind::Integer(bits, self.sign),
26-
IntegerRigidity::Loose(c_integer) => {
27-
resolved::TypeKind::CInteger(c_integer, Some(self.sign))
24+
IntegerRigidity::Fixed(bits, sign) => resolved::TypeKind::Integer(bits, sign),
25+
IntegerRigidity::Loose(c_integer, sign) => {
26+
resolved::TypeKind::CInteger(c_integer, sign)
2827
}
2928
}
3029
.at(source)
@@ -33,8 +32,8 @@ impl IntegerKnown {
3332

3433
#[derive(Clone, Debug)]
3534
pub enum IntegerRigidity {
36-
Fixed(IntegerBits),
37-
Loose(CInteger),
35+
Fixed(IntegerBits, IntegerSign),
36+
Loose(CInteger, Option<IntegerSign>),
3837
}
3938

4039
impl Integer {

src/ast/expr/kind.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub enum ExprKind {
1414
Float(f64),
1515
String(String),
1616
NullTerminatedString(CString),
17+
CharLiteral(u8),
1718
Call(Box<Call>),
1819
DeclareAssign(Box<DeclareAssign>),
1920
BasicBinaryOperation(Box<BasicBinaryOperation>),

src/c/translation/expr/integer.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,28 @@ use crate::{
88
pub fn translate_expr_integer(integer: &Integer, source: Source) -> Result<ast::Expr, ParseError> {
99
let known = match integer {
1010
Integer::Int(x) => IntegerKnown {
11-
rigidity: IntegerRigidity::Loose(CInteger::Int),
11+
rigidity: IntegerRigidity::Loose(CInteger::Int, Some(IntegerSign::Signed)),
1212
value: (*x).into(),
13-
sign: IntegerSign::Signed,
1413
},
1514
Integer::UnsignedInt(x) => IntegerKnown {
16-
rigidity: IntegerRigidity::Loose(CInteger::Int),
15+
rigidity: IntegerRigidity::Loose(CInteger::Int, Some(IntegerSign::Unsigned)),
1716
value: (*x).into(),
18-
sign: IntegerSign::Unsigned,
1917
},
2018
Integer::Long(x) => IntegerKnown {
21-
rigidity: IntegerRigidity::Loose(CInteger::Long),
19+
rigidity: IntegerRigidity::Loose(CInteger::Long, Some(IntegerSign::Signed)),
2220
value: (*x).into(),
23-
sign: IntegerSign::Signed,
2421
},
2522
Integer::UnsignedLong(x) => IntegerKnown {
26-
rigidity: IntegerRigidity::Loose(CInteger::Long),
23+
rigidity: IntegerRigidity::Loose(CInteger::Long, Some(IntegerSign::Unsigned)),
2724
value: (*x).into(),
28-
sign: IntegerSign::Unsigned,
2925
},
3026
Integer::LongLong(x) => IntegerKnown {
31-
rigidity: IntegerRigidity::Loose(CInteger::LongLong),
27+
rigidity: IntegerRigidity::Loose(CInteger::LongLong, Some(IntegerSign::Signed)),
3228
value: (*x).into(),
33-
sign: IntegerSign::Signed,
3429
},
3530
Integer::UnsignedLongLong(x) => IntegerKnown {
36-
rigidity: IntegerRigidity::Loose(CInteger::LongLong),
31+
rigidity: IntegerRigidity::Loose(CInteger::LongLong, Some(IntegerSign::Unsigned)),
3732
value: (*x).into(),
38-
sign: IntegerSign::Unsigned,
3933
},
4034
};
4135

src/lexer/mod.rs

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,16 @@ impl<T: Text + Send> Lexer<T> {
291291
});
292292
Waiting
293293
}
294+
'c' if self.characters.peek().is('\'') => {
295+
// C `char` literal
296+
self.state = State::String(StringState {
297+
value: String::new(),
298+
closing_char: self.characters.next().unwrap().0,
299+
modifier: StringModifier::CharLiteral,
300+
start_source: source,
301+
});
302+
Waiting
303+
}
294304
_ if c.is_alphabetic() || c == '_' => {
295305
self.state = State::Identifier(IdentifierState {
296306
identifier: String::from(c),
@@ -355,40 +365,46 @@ impl<T: Text + Send> Lexer<T> {
355365

356366
let state = self.state.as_mut_string();
357367

358-
match self.characters.next() {
359-
Character::At(c, c_source) => {
360-
if c == state.closing_char {
361-
let value = std::mem::take(&mut state.value);
362-
let modifier = state.modifier;
363-
let start_source = state.start_source;
364-
self.state = State::Idle;
365-
366-
Has(TokenKind::String(StringLiteral { value, modifier }).at(start_source))
367-
} else if c == '\\' {
368-
if let Character::At(next_c, _) = self.characters.next() {
369-
match next_c {
370-
'n' => state.value.push('\n'),
371-
'r' => state.value.push('\r'),
372-
't' => state.value.push('\t'),
373-
_ => state.value.push(next_c),
374-
}
375-
376-
Waiting
377-
} else {
378-
Has(
379-
TokenKind::Error("Expected character after string esacpe '\\'".into())
380-
.at(c_source),
381-
)
382-
}
383-
} else {
384-
state.value.push(c);
385-
Waiting
368+
let Character::At(c, c_source) = self.characters.next() else {
369+
let message = match state.modifier {
370+
StringModifier::Normal | StringModifier::NullTerminated => {
371+
"Unclosed string literal"
386372
}
387-
}
388-
Character::End(_) => {
389-
Has(TokenKind::Error("Unclosed string literal".into()).at(state.start_source))
390-
}
373+
StringModifier::CharLiteral => "Unclosed character literal",
374+
};
375+
376+
return Has(TokenKind::Error(message.into()).at(state.start_source));
377+
};
378+
379+
if c == state.closing_char {
380+
let value = std::mem::take(&mut state.value);
381+
let modifier = state.modifier;
382+
let start_source = state.start_source;
383+
self.state = State::Idle;
384+
385+
return Has(TokenKind::String(StringLiteral { value, modifier }).at(start_source));
386+
}
387+
388+
if c != '\\' {
389+
state.value.push(c);
390+
return Waiting;
391391
}
392+
393+
let Character::At(next_c, _) = self.characters.next() else {
394+
return Has(
395+
TokenKind::Error("Expected character after escaping '\\'".into()).at(c_source),
396+
);
397+
};
398+
399+
match next_c {
400+
'n' => state.value.push('\n'),
401+
'r' => state.value.push('\r'),
402+
't' => state.value.push('\t'),
403+
'"' | '\'' => state.value.push(next_c),
404+
_ => return Has(TokenKind::Error("Unrecognized escape sequence".into()).at(c_source)),
405+
}
406+
407+
Waiting
392408
}
393409

394410
fn feed_number(&mut self) -> FeedResult<Token> {

src/lower/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -472,13 +472,17 @@ fn lower_expr(
472472
}
473473
ExprKind::IntegerKnown(integer) => {
474474
let value = &integer.value;
475-
let sign = &integer.sign;
476475

477-
let bits = match &integer.rigidity {
478-
IntegerRigidity::Fixed(bits) => *bits,
479-
IntegerRigidity::Loose(c_integer) => {
480-
IntegerBits::try_from(c_integer.bytes(&ir_module.target))
481-
.expect("supported integer size")
476+
let (bits, sign) = match &integer.rigidity {
477+
IntegerRigidity::Fixed(bits, sign) => (*bits, *sign),
478+
IntegerRigidity::Loose(c_integer, sign) => {
479+
let bits = IntegerBits::try_from(c_integer.bytes(&ir_module.target))
480+
.expect("supported integer size");
481+
482+
let sign =
483+
sign.unwrap_or_else(|| ir_module.target.default_c_integer_sign(*c_integer));
484+
485+
(bits, sign)
482486
}
483487
};
484488

src/parser/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub enum ParseErrorKind {
8585
},
8686
GenericsNotSupportedHere,
8787
NamespaceNotAllowedHere,
88+
CharLiteralCannotBeLargerThanOneByte,
8889
Other {
8990
message: String,
9091
},
@@ -211,6 +212,9 @@ impl Display for ParseErrorKind {
211212
ParseErrorKind::NamespaceNotAllowedHere => {
212213
write!(f, "Namespace not allowed here")?;
213214
}
215+
ParseErrorKind::CharLiteralCannotBeLargerThanOneByte => {
216+
write!(f, "char literal cannot be larger than 1 byte")?;
217+
}
214218
ParseErrorKind::Other { message } | ParseErrorKind::Lexical { message } => {
215219
write!(f, "{}", message)?;
216220
}

src/parser/parse_expr/primary/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
6767
},
6868
source,
6969
)),
70+
TokenKind::String(StringLiteral {
71+
modifier: StringModifier::CharLiteral,
72+
..
73+
}) => {
74+
let content = self.input.advance().kind.unwrap_string().value;
75+
76+
if content.len() != 1 {
77+
return Err(ParseErrorKind::CharLiteralCannotBeLargerThanOneByte.at(source));
78+
}
79+
80+
Ok(Expr::new(
81+
ExprKind::CharLiteral(content.as_bytes()[0]),
82+
source,
83+
))
84+
}
7085
TokenKind::OpenParen => {
7186
self.input.advance().kind.unwrap_open_paren();
7287
let inner = self.parse_expr()?;

src/resolve/conform/from_integer_literal.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ fn from_integer_literal_to_integer(
4747
TypedExpr::new(
4848
TypeKind::Integer(to_bits, to_sign).at(source),
4949
ExprKind::IntegerKnown(Box::new(IntegerKnown {
50-
rigidity: IntegerRigidity::Fixed(to_bits),
50+
rigidity: IntegerRigidity::Fixed(to_bits, to_sign),
5151
value: value.clone(),
52-
sign: to_sign,
5352
}))
5453
.at(source),
5554
)
@@ -70,9 +69,8 @@ fn from_integer_literal_to_c_integer(
7069
TypedExpr::new(
7170
TypeKind::CInteger(to_c_integer, to_sign).at(source),
7271
ExprKind::IntegerKnown(Box::new(IntegerKnown {
73-
rigidity: IntegerRigidity::Loose(to_c_integer),
72+
rigidity: IntegerRigidity::Loose(to_c_integer, to_sign),
7473
value: value.clone(),
75-
sign: to_sign.unwrap_or(IntegerSign::Signed),
7674
}))
7775
.at(source),
7876
)

src/resolve/expr/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ pub fn resolve_expr(
147147
resolved::ExprKind::IntegerKnown(Box::new(IntegerKnown {
148148
rigidity: known.rigidity.clone(),
149149
value: known.value.clone(),
150-
sign: known.sign,
151150
}))
152151
.at(source),
153152
),
@@ -159,6 +158,18 @@ pub fn resolve_expr(
159158

160159
Ok(TypedExpr::new(resolved_type, expr))
161160
}
161+
ast::ExprKind::CharLiteral(value) => {
162+
let expr = resolved::ExprKind::IntegerKnown(Box::new(IntegerKnown {
163+
rigidity: ast::IntegerRigidity::Loose(CInteger::Char, None),
164+
value: (*value).into(),
165+
}))
166+
.at(source);
167+
168+
Ok(TypedExpr::new(
169+
resolved::TypeKind::CInteger(CInteger::Char, None).at(source),
170+
expr,
171+
))
172+
}
162173
ast::ExprKind::Float(value) => Ok(TypedExpr::new(
163174
resolved::TypeKind::FloatLiteral(*value).at(source),
164175
resolved::Expr::new(

0 commit comments

Comments
 (0)