Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bin, oct and hex literals #183

Merged
merged 3 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .run/Spice_run.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O0 -ir ../../media/test-project/os-test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O2 -ir ../../media/test-project/os-test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<envs>
<env name="RUN_TESTS" value="OFF" />
</envs>
Expand Down
47 changes: 47 additions & 0 deletions docs/docs/language/number-formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Number formats
---

Spice supports four different number formats to cover as many use-cases as possible.

## Decimal format (base 10)

Decimal numbers can be written in two ways in Spice. The implicit way:

```spice
int i32 = 123;
short i16 = 123s;
long i64 = 123l;
```

or the explicit way:

```spice
int i32 = 0d123;
short i16 = 0d123s;
long i64 = 0d123l;
```

## Binary format (base 2)

```spice
int i32 = 0b1010;
short i16 = 0b1010s;
long i64 = 0b1010l;
```

## Hexadecimal format (base 16)

```spice
int i32 = 0xA76E;
short i16 = 0xA76Es;
long i64 = 0xA76El;
```

## Octal format (base 8)

```spice
int i32 = 0o1274;
short i16 = 0o1274s;
long i64 = 0o1274l;
```
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ nav:
- language/constructors-destructors.md
- language/generics.md
#- language/threads.md
- language/number-formats.md
- language/operator-precedence.md
- contributing.md

Expand Down
8 changes: 1 addition & 7 deletions media/test-project/os-test.spice
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,5 @@ f<int> main() {
}*/

f<int> main() {
int[10][10] a;
for int i = 0; i < 10; i++ {
for int j = 0; j < 10; j++ {
a[i][j] = i * j;
}
}
printf("Cell [1,3]: %d", a[1][3]);
printf("Test: %d\n", 0o0000777);
}
19 changes: 10 additions & 9 deletions src/Spice.g4
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,19 @@ DOT: '.';
ELLIPSIS: '...';

// Regex tokens
DOUBLE_LIT: [0-9]*[.][0-9]+;
INT_LIT: NUM_LIT;
SHORT_LIT: NUM_LIT 's';
LONG_LIT: NUM_LIT 'l';
CHAR_LIT: '\'' (~['\\\r\n] | '\\' (. | EOF)) '\'';
STRING_LIT: '"' (~["\\\r\n] | '\\' (. | EOF))* '"';
INT_LIT: NONZERO_DIGIT DIGIT* | ZERO;
DOUBLE_LIT: DIGIT+ DOT DIGIT+;
SHORT_LIT: INT_LIT 's';
LONG_LIT: INT_LIT 'l';
IDENTIFIER: NONDIGIT (NONDIGIT | DIGIT)*;
IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]*;

fragment ZERO: [0];
fragment DIGIT: [0-9];
fragment NONZERO_DIGIT: [1-9];
fragment NONDIGIT: [a-zA-Z_];
fragment NUM_LIT: DEC_LIT | BIN_LIT | HEX_LIT | OCT_LIT;
fragment DEC_LIT: ([0][dD])?[0-9]+;
fragment BIN_LIT: [0][bB][01]+;
fragment HEX_LIT: [0][xXhH][0-9a-fA-F]+;
fragment OCT_LIT: [0][oO][0-7]+;

// Skipped tokens
BLOCK_COMMENT: '/*' .*? '*/' -> skip;
Expand Down
70 changes: 62 additions & 8 deletions src/parser/AstBuilderVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,24 +1197,21 @@ std::any AstBuilderVisitor::visitPrimitiveValue(SpiceParser::PrimitiveValueConte
primitiveValueNode->data.doubleValue = std::stod(t->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::INT_LIT) {
primitiveValueNode->type = PrimitiveValueNode::TY_INT;
primitiveValueNode->data.intValue = std::stoi(t->toString());
primitiveValueNode->data.intValue = parseInt(t->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree);
t->getSymbol()->getType() == SpiceParser::SHORT_LIT) {
primitiveValueNode->type = PrimitiveValueNode::TY_SHORT;
primitiveValueNode->data.shortValue = (short)std::stoi(t->toString());
primitiveValueNode->data.shortValue = parseShort(t->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::LONG_LIT) {
primitiveValueNode->type = PrimitiveValueNode::TY_LONG;
primitiveValueNode->data.longValue = std::stoll(t->toString());
primitiveValueNode->data.longValue = parseLong(t->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::CHAR_LIT) {
primitiveValueNode->type = PrimitiveValueNode::TY_CHAR;
primitiveValueNode->data.charValue = ctx->CHAR_LIT()->toString()[1];
primitiveValueNode->data.charValue = parseChar(ctx->CHAR_LIT()->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree);
t->getSymbol()->getType() == SpiceParser::STRING_LIT) {
primitiveValueNode->type = PrimitiveValueNode::TY_STRING;
std::string strValue = ctx->STRING_LIT()->toString();
strValue = strValue.substr(1, strValue.size() - 2);
replaceEscapeChars(strValue);
primitiveValueNode->data.stringValue = strValue;
primitiveValueNode->data.stringValue = parseString(ctx->STRING_LIT()->toString());
} else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::TRUE) {
primitiveValueNode->type = PrimitiveValueNode::TY_BOOL;
primitiveValueNode->data.boolValue = true;
Expand Down Expand Up @@ -1479,4 +1476,61 @@ void AstBuilderVisitor::replaceEscapeChars(std::string &string) {
CommonUtil::replaceAll(string, "\\v", "\v");
CommonUtil::replaceAll(string, "\\'", "\'");
CommonUtil::replaceAll(string, "\\?", "\?");
}

int32_t AstBuilderVisitor::parseInt(const std::string &input) {
std::function<int32_t(const std::string &, int)> cb = [](const std::string &substr, int base) {
return std::stoi(substr, nullptr, base);
};
return parseNumeric(input, cb);
}
int16_t AstBuilderVisitor::parseShort(const std::string &input) {
std::function<int16_t(const std::string &, int)> cb = [](const std::string &substr, int base) {
return (int16_t)std::stoi(substr, nullptr, base);
};
return parseNumeric(input, cb);
}

int64_t AstBuilderVisitor::parseLong(const std::string &input) {
std::function<int64_t(const std::string &, int)> cb = [](const std::string &substr, int base) {
return std::stoll(substr, nullptr, base);
};
return parseNumeric(input, cb);
}

int8_t AstBuilderVisitor::parseChar(const std::string &input) { return input[1]; }

std::string AstBuilderVisitor::parseString(std::string input) {
input = input.substr(1, input.size() - 2);
replaceEscapeChars(input);
return input;
}

template <typename T> T AstBuilderVisitor::parseNumeric(const std::string &input, std::function<T(const std::string &, int)> cb) {
if (input.length() >= 3) {
char c1 = input[0];
char c2 = input[1];
std::string substr = input.substr(2);
if (c1 == '0') {
switch (c2) {
case 'd':
case 'D':
return cb(substr, 10);
case 'b':
case 'B':
return cb(substr, 2);
case 'h':
case 'H':
case 'x':
case 'X':
return cb(substr, 16);
case 'o':
case 'O':
return cb(substr, 8);
default:
return cb(input, 10);
}
}
}
return cb(input, 10);
}
7 changes: 7 additions & 0 deletions src/parser/AstBuilderVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <SpiceVisitor.h>

#include <functional>
#include <utility>

// Forward declarations
Expand Down Expand Up @@ -86,5 +87,11 @@ class AstBuilderVisitor : public SpiceVisitor {
std::string fileName;

// Private methods
static int32_t parseInt(const std::string &input);
static int16_t parseShort(const std::string &input);
static int64_t parseLong(const std::string &input);
static int8_t parseChar(const std::string &input);
static std::string parseString(std::string input);
template <typename T> T static parseNumeric(const std::string &input, std::function<T(const std::string &, int)> cb);
static void replaceEscapeChars(std::string &string);
};
34 changes: 17 additions & 17 deletions std/io/dir_linux.spice
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
//import "std/os/os" as os;

// File permission modes
public const int MODE_ALL_RWX = 511; // Decimal for octal: 0000777
public const int MODE_ALL_RW = 438; // Decimal for octal: 0000666
public const int MODE_ALL_R = 292; // Decimal for octal: 0000444
public const int MODE_ALL_RWX = 0o0000777;
public const int MODE_ALL_RW = 0o0000666;
public const int MODE_ALL_R = 0o0000444;

public const int MODE_OWNER_RWX = 448; // Decimal for octal: 0000700
public const int MODE_OWNER_R = 256; // Decimal for octal: 0000400
public const int MODE_OWNER_W = 128; // Decimal for octal: 0000200
public const int MODE_OWNER_X = 64; // Decimal for octal: 0000100
public const int MODE_OWNER_RWX = 0o0000700;
public const int MODE_OWNER_R = 0o0000400;
public const int MODE_OWNER_W = 0o0000200;
public const int MODE_OWNER_X = 0o0000100;

public const int MODE_GROUP_RWX = 56; // Decimal for octal: 0000070
public const int MODE_GROUP_R = 32; // Decimal for octal: 0000040
public const int MODE_GROUP_W = 16; // Decimal for octal: 0000020
public const int MODE_GROUP_X = 8; // Decimal for octal: 0000010
public const int MODE_GROUP_RWX = 0o0000070;
public const int MODE_GROUP_R = 0o0000040;
public const int MODE_GROUP_W = 0o0000020;
public const int MODE_GROUP_X = 0o0000010;

public const int MODE_OTHER_RWX = 7; // Decimal for octal: 0000007
public const int MODE_OTHER_R = 4; // Decimal for octal: 0000004
public const int MODE_OTHER_W = 2; // Decimal for octal: 0000002
public const int MODE_OTHER_X = 1; // Decimal for octal: 0000001
public const int MODE_OTHER_RWX = 0o0000007;
public const int MODE_OTHER_R = 0o0000004;
public const int MODE_OTHER_W = 0o0000002;
public const int MODE_OTHER_X = 0o0000001;

const int F_OK = 0; // File existence
const int X_OK = 1; // Can execute
const int W_OK = 2; // Can write
const int R_OK = 4; // Can read

const int IF_MT = 61440; // Decimal for octal: 0170000
const int IF_DIR = 16384; // Decimal for octal: 0040000
const int IF_MT = 0o0170000;
const int IF_DIR = 0o0040000;

type FileStat struct { // Total size: 46 bytes
unsigned long st_dev // ID of the device containing file
Expand Down
36 changes: 18 additions & 18 deletions std/io/dir_windows.spice
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
//import "std/os/os" as os;

// File permission modes
public const int MODE_ALL_RWX = 511; // Decimal for octal: 0000777
public const int MODE_ALL_RW = 438; // Decimal for octal: 0000666
public const int MODE_ALL_R = 292; // Decimal for octal: 0000444

public const int MODE_OWNER_RWX = 448; // Decimal for octal: 0000700
public const int MODE_OWNER_R = 256; // Decimal for octal: 0000400
public const int MODE_OWNER_W = 128; // Decimal for octal: 0000200
public const int MODE_OWNER_X = 64; // Decimal for octal: 0000100

public const int MODE_GROUP_RWX = 56; // Decimal for octal: 0000070
public const int MODE_GROUP_R = 32; // Decimal for octal: 0000040
public const int MODE_GROUP_W = 16; // Decimal for octal: 0000020
public const int MODE_GROUP_X = 8; // Decimal for octal: 0000010

public const int MODE_OTHER_RWX = 7; // Decimal for octal: 0000007
public const int MODE_OTHER_R = 4; // Decimal for octal: 0000004
public const int MODE_OTHER_W = 2; // Decimal for octal: 0000002
public const int MODE_OTHER_X = 1; // Decimal for octal: 0000001
public const int MODE_ALL_RWX = 0o0000777;
public const int MODE_ALL_RW = 0o0000666;
public const int MODE_ALL_R = 0o0000444;

public const int MODE_OWNER_RWX = 0o0000700;
public const int MODE_OWNER_R = 0o0000400;
public const int MODE_OWNER_W = 0o0000200;
public const int MODE_OWNER_X = 0o0000100;

public const int MODE_GROUP_RWX = 0o0000070;
public const int MODE_GROUP_R = 0o0000040;
public const int MODE_GROUP_W = 0o0000020;
public const int MODE_GROUP_X = 0o0000010;

public const int MODE_OTHER_RWX = 0o0000007;
public const int MODE_OTHER_R = 0o0000004;
public const int MODE_OTHER_W = 0o0000002;
public const int MODE_OTHER_X = 0o0000001;

const int F_OK = 0; // File existence
const int X_OK = 1; // Can execute
Expand Down
28 changes: 14 additions & 14 deletions std/io/file_linux.spice
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// File open modes
public const string MODE_READ = "r";
public const string MODE_WRITE = "w";
public const string MODE_APPEND = "a";
public const string MODE_READ_WRITE = "r+";
public const string MODE_READ_WRITE_OVERWRITE = "w+";
public const string MODE_READ_WRITE_APPEND = "a+";
public const string MODE_READ = "r";
public const string MODE_WRITE = "w";
public const string MODE_APPEND = "a";
public const string MODE_READ_WRITE = "r+";
public const string MODE_READ_WRITE_OVERWRITE = "w+";
public const string MODE_READ_WRITE_APPEND = "a+";

const int MODE_CREATE = 64; // Decimal for octal: 100
const int MODE_RDWR = 2; // Decimal for octal: 2
const int MODE_CREATE = 0o100;
const int MODE_RDWR = 0o002;

const int F_OK = 0; // File existence
const int X_OK = 1; // Can execute
Expand Down Expand Up @@ -50,7 +50,7 @@ public f<int> createFile(string path) {

/**
* Opens a (new) file at the specified path with the specified mode.
*
*
* There are predefined constants for the mode available:
* MODE_READ, MODE_WRITE, MODE_APPEND,
* MODE_READ_WRITE, MODE_READ_WRITE_OVERWRITE, MODE_READ_WRITE_APPEND
Expand Down Expand Up @@ -84,7 +84,7 @@ public f<int> File.readChar() {

/**
* Writes a single character to the file.
*
*
* @return Result code of the write operation: 0 = successful, -1 = failed
*/
public f<int> File.writeChar(char value) {
Expand Down Expand Up @@ -169,7 +169,7 @@ public f<long> getFileSize(string path) {

/**
* Checks if a file exists. The function also returns true if the specified path points to a directory.
*
*
* @return Existing / not existing
*/
public f<bool> fileExists(string path) {
Expand All @@ -178,7 +178,7 @@ public f<bool> fileExists(string path) {

/**
* Checks if the read permissions to a file are given.
*
*
* @return Readable / not readable
*/
public f<bool> fileReadable(string path) {
Expand All @@ -187,7 +187,7 @@ public f<bool> fileReadable(string path) {

/**
* Checks if the write permissions to a file are given.
*
*
* @return Writable / not writable
*/
public f<bool> fileWritable(string path) {
Expand All @@ -196,7 +196,7 @@ public f<bool> fileWritable(string path) {

/**
* Checks if the execute permissions to a file are given.
*
*
* @return Executable / not executable
*/
public f<bool> fileExecutable(string path) {
Expand Down
Loading