Skip to content

Commit

Permalink
feat: implement integer literal
Browse files Browse the repository at this point in the history
  • Loading branch information
kiwiyou authored and RanolP committed Nov 20, 2023
1 parent 102f3f6 commit a84b836
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 1 deletion.
6 changes: 6 additions & 0 deletions crates/psl/src/ast/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ use super::{ExpressionOrBlock, Token, Type};

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum Expression {
Literal(LiteralExpression),
Read(ReadExpression),
Name(NameExpression),
If(IfExpression),
BinaryOperator(BinaryOperatorExpression),
}

#[derive(Clone, Debug, Hash, PartialEq)]

Check warning on line 12 in crates/psl/src/ast/expressions.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/ast/expressions.rs#L12

Added line #L12 was not covered by tests
pub struct LiteralExpression {
pub value: Token,
}

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum ReadExpression {
Type(Type),
Expand Down
4 changes: 4 additions & 0 deletions crates/psl/src/ast/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub enum TokenKind {

IdentifierIdentifier,

LiteralDecimal,
LiteralHexadecimal,
LiteralBinary,

KeywordRead,
KeywordWrite,
KeywordIf,
Expand Down
70 changes: 70 additions & 0 deletions crates/psl/src/codegen/impls/expressions/literal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::{
ast::{LiteralExpression, TokenKind},
codegen::{
construct::Type,
context::CodegenContext,
pass::{NameResolutionContext, NameResolutionPass},
visitor::CodegenNode,
},
};

impl CodegenNode for LiteralExpression {
fn produce_code(self, _ctx: &mut CodegenContext) -> String {
let digit_only = self.value.content.replace('_', "");
match self.value.kind {
TokenKind::LiteralDecimal => digit_only,
TokenKind::LiteralHexadecimal => format!("0x{digit_only}"),

Check warning on line 16 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L12-L16

Added lines #L12 - L16 were not covered by tests
TokenKind::LiteralBinary => {
let mut binary = String::from("0x");
let mut buffer = 0;
let mut nibble_len = digit_only.chars().count() % 4;
for bit in digit_only.chars() {
buffer <<= 1;
if bit == '1' {
buffer |= 1;
}
nibble_len -= 1;
if nibble_len == 0 {
binary.push(to_hex_digit(buffer));
}

Check warning on line 29 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L18-L29

Added lines #L18 - L29 were not covered by tests
}
binary

Check warning on line 31 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L31

Added line #L31 was not covered by tests
}
_ => unreachable!(
"Invalid TokenKind for LiteralExpression: {:?}",
self.value.kind
),

Check warning on line 36 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L33-L36

Added lines #L33 - L36 were not covered by tests
}
}

Check warning on line 38 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L38

Added line #L38 was not covered by tests
}
impl NameResolutionPass for LiteralExpression {
fn resolve(&self, _ctx: &mut NameResolutionContext) {}

Check warning on line 41 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L41

Added line #L41 was not covered by tests
}

impl LiteralExpression {
pub fn infer_type(&self, _ctx: &CodegenContext) -> Result<Type, String> {
Ok(Type::Integer)
}

Check warning on line 47 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L45-L47

Added lines #L45 - L47 were not covered by tests
}

fn to_hex_digit(number: i32) -> char {
match number {
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
6 => '6',
7 => '7',
8 => '8',
9 => '9',
10 => 'A',
11 => 'B',
12 => 'C',
13 => 'D',
14 => 'E',
15 => 'F',
_ => unreachable!("No matching hex digit for {number}"),

Check warning on line 68 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L50-L68

Added lines #L50 - L68 were not covered by tests
}
}

Check warning on line 70 in crates/psl/src/codegen/impls/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/literal.rs#L70

Added line #L70 was not covered by tests
4 changes: 4 additions & 0 deletions crates/psl/src/codegen/impls/expressions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod binary_operator;
mod r#if;
mod literal;
mod name;
mod read;

Expand All @@ -16,6 +17,7 @@ use crate::{
impl CodegenNode for Expression {
fn produce_code(self, ctx: &mut CodegenContext) -> String {
match self {
Expression::Literal(node) => ctx.visit(node),

Check warning on line 20 in crates/psl/src/codegen/impls/expressions/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/mod.rs#L20

Added line #L20 was not covered by tests
Expression::Read(node) => ctx.visit(node),
Expression::Name(node) => ctx.visit(node),
Expression::If(node) => ctx.visit(node),
Expand All @@ -27,6 +29,7 @@ impl CodegenNode for Expression {
impl NameResolutionPass for Expression {
fn resolve(&self, ctx: &mut NameResolutionContext) {
match self {
Expression::Literal(node) => ctx.visit(node),

Check warning on line 32 in crates/psl/src/codegen/impls/expressions/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/mod.rs#L32

Added line #L32 was not covered by tests
Expression::Read(node) => ctx.visit(node),
Expression::Name(node) => ctx.visit(node),
Expression::If(node) => ctx.visit(node),
Expand All @@ -38,6 +41,7 @@ impl NameResolutionPass for Expression {
impl Expression {
pub fn infer_type(&self, ctx: &CodegenContext) -> Result<Type, String> {
match self {
Expression::Literal(expr) => expr.infer_type(ctx),

Check warning on line 44 in crates/psl/src/codegen/impls/expressions/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/codegen/impls/expressions/mod.rs#L44

Added line #L44 was not covered by tests
Expression::Read(expr) => expr.infer_type(ctx),
Expression::Name(expr) => expr.infer_type(ctx),
Expression::If(expr) => expr.infer_type(ctx),
Expand Down
13 changes: 13 additions & 0 deletions crates/psl/src/syntax/expressions/literal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use winnow::{combinator::alt, Located, PResult, Parser};

use crate::ast::{LiteralExpression, TokenKind};

pub fn parse_literal(s: &mut Located<&str>) -> PResult<LiteralExpression> {
alt((
TokenKind::LiteralDecimal,
TokenKind::LiteralHexadecimal,
TokenKind::LiteralBinary,
))
.map(|token| LiteralExpression { value: token })
.parse_next(s)
}

Check warning on line 13 in crates/psl/src/syntax/expressions/literal.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/syntax/expressions/literal.rs#L5-L13

Added lines #L5 - L13 were not covered by tests
1 change: 1 addition & 0 deletions crates/psl/src/syntax/expressions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub use name::parse_name;
use operator::parse_operator;

mod r#if;
mod literal;
mod name;
mod operator;
mod read;
Expand Down
3 changes: 2 additions & 1 deletion crates/psl/src/syntax/expressions/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use winnow::{combinator::alt, Located, PResult, Parser};

use crate::ast::Expression;

use super::{name::parse_name, r#if::parse_if, read::parse_read};
use super::{literal::parse_literal, name::parse_name, r#if::parse_if, read::parse_read};

pub fn parse_simple_expression(s: &mut Located<&str>) -> PResult<Expression> {
alt((
parse_literal.map(Expression::Literal),

Check warning on line 9 in crates/psl/src/syntax/expressions/simple.rs

View check run for this annotation

Codecov / codecov/patch

crates/psl/src/syntax/expressions/simple.rs#L9

Added line #L9 was not covered by tests
parse_read.map(Expression::Read),
parse_name.map(Expression::Name),
parse_if.map(Expression::If),
Expand Down
44 changes: 44 additions & 0 deletions crates/psl/src/syntax/tokens/literal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use winnow::{
combinator::{alt, preceded},
token::take_while,
Located, PResult, Parser,
};

use crate::ast::{Token, TokenKind};

use super::token;

pub fn parse_literal(s: &mut Located<&str>) -> PResult<Token> {
parse_integer_literal.parse_next(s)
}

pub fn parse_integer_literal(s: &mut Located<&str>) -> PResult<Token> {
alt((parse_hexadecimal, parse_binary, parse_decimal)).parse_next(s)
}

pub fn parse_decimal(s: &mut Located<&str>) -> PResult<Token> {
take_while(1.., ('0'..='9', '_'))
.verify(|s: &str| s.chars().any(|c| c != '_'))
.with_span()
.map(token(TokenKind::LiteralDecimal))
.parse_next(s)
}

pub fn parse_hexadecimal(s: &mut Located<&str>) -> PResult<Token> {
preceded(
"0x",
take_while(1.., ('0'..='9', 'a'..='f', 'A'..='F', '_')),
)
.verify(|s: &str| s.chars().any(|c| c != '_'))
.with_span()
.map(token(TokenKind::LiteralHexadecimal))
.parse_next(s)
}

pub fn parse_binary(s: &mut Located<&str>) -> PResult<Token> {
preceded("0b", take_while(1.., ('0'..='1', '_')))
.verify(|s: &str| s.chars().any(|c| c != '_'))
.with_span()
.map(token(TokenKind::LiteralBinary))
.parse_next(s)
}
3 changes: 3 additions & 0 deletions crates/psl/src/syntax/tokens/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ use crate::ast::{Token, TokenKind};
use self::{
identifier::parse_identifier_identifier,
keyword::parse_keyword,
literal::parse_literal,
punctuations::parse_punctuations,
whitespaces::{parse_whitespace_horizontal, parse_whitespace_vertical},
};

mod identifier;
mod keyword;
mod literal;
mod punctuations;
mod whitespaces;

Expand All @@ -28,6 +30,7 @@ pub fn parse_token(s: &mut Located<&str>) -> PResult<Token> {
parse_whitespace_horizontal,
parse_whitespace_vertical,
parse_identifier_identifier,
parse_literal,
any.with_span().map(token(TokenKind::Error)),
success("<eof>").with_span().map(token(TokenKind::Eof)),
))
Expand Down
16 changes: 16 additions & 0 deletions snippets/27xx/2753.psl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
i32 year = read i32
i32 is_leap = if year % 4 == 0 {
if year % 400 == 0 {
1
} else {
if year % 100 == 0 {
0
} else {
1
}
}
} else {
0
}

write is_leap

0 comments on commit a84b836

Please sign in to comment.