forked from solstice/solstice
Compare commits
83 Commits
5196f73e16
...
rewrite
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c0490668e | |||
| e5da1d255b | |||
| c0c35e4d17 | |||
| f67c045845 | |||
| 98c8775208 | |||
| f384e19c06 | |||
| d24462f844 | |||
| 4351821d30 | |||
| 78f974e189 | |||
| 1dedb30a87 | |||
| 2e7b5b7480 | |||
| 1cf995f7ac | |||
| 605d0a87b1 | |||
| 16569d7355 | |||
| fd08b7cdb7 | |||
| 5841a7a999 | |||
| a2fc138ba1 | |||
| 9b55b509f5 | |||
| f694f50d70 | |||
| 5b61a11f00 | |||
| 00d6ed83fb | |||
| 6988f314b0 | |||
| 70dc5eb5a0 | |||
| 1e3bd6c601 | |||
| f66464a7cc | |||
| 631b587d07 | |||
| 445ba032f5 | |||
| 41a2fa53c6 | |||
| 00ef8a7d56 | |||
| f1eee4f6a8 | |||
| cfca3c1d7a | |||
| 40e0aec0d4 | |||
| 38473f0e01 | |||
| 139be30e2d | |||
| d576c7cdfc | |||
| 2e4dbce100 | |||
| ea6bf5925b | |||
| 142268c016 | |||
| 1c6b145d35 | |||
| 6002bd922b | |||
| 4b86fee7b5 | |||
| d12036fe70 | |||
| 59e273b26e | |||
| e285b2c59f | |||
| e3abe07f4b | |||
| 010d155f5d | |||
| 44785185f7 | |||
| c82f81f668 | |||
| 9397f410da | |||
| 6d5d29f05b | |||
| 48c130351a | |||
| 6bc483b1db | |||
| c5b67bff72 | |||
| ca8db171d9 | |||
| c266728ff0 | |||
| b46a66cea7 | |||
| 337b88c148 | |||
| d8812fa14e | |||
| 24ea348858 | |||
| 9a311c3cb8 | |||
| aa5ef0e664 | |||
| 7ff306b9e8 | |||
| ac7f22e1bc | |||
| 5ec2f86b70 | |||
| 7dd2b10603 | |||
| 7351604571 | |||
| 43310c70bf | |||
| 957e0fd95a | |||
| 525b2bc733 | |||
| d2f295f46a | |||
| 869f71466e | |||
| a3a9553189 | |||
| 3c66df5be0 | |||
| ce058c8f9c | |||
| 2aff15a317 | |||
| 72ec9c1fb6 | |||
| c04e631180 | |||
| 16a406b52f | |||
| 0488067ef2 | |||
| a8e5f6a0f1 | |||
| e8bf7b70f7 | |||
| b5c8b1b7ec | |||
| 99bc0dbdc2 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
hg
|
||||
solstice
|
||||
build
|
||||
.*_solsbuild
|
||||
|
||||
5
.project.fish
Normal file
5
.project.fish
Normal file
@@ -0,0 +1,5 @@
|
||||
# source .project.fish
|
||||
|
||||
alias run "make && ./solstice"
|
||||
alias clean "make clean"
|
||||
alias cleanrun "make clean && make && ./solstice"
|
||||
42
README.md
42
README.md
@@ -1,49 +1,21 @@
|
||||
# High Ground
|
||||

|
||||
|
||||
High Ground is a programming language based on Ground.
|
||||
# Solstice
|
||||
|
||||
It is the reference language designed to teach you how to build your own Ground-based language.
|
||||
Solstice is a programming language based on Ground.
|
||||
|
||||
## Compiling
|
||||
|
||||
First, ensure CGround is installed on your system with `sudo make install`. Then, compile with
|
||||
|
||||
```
|
||||
g++ src/main.cpp -o hg -lgroundvm
|
||||
make
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
High Ground files use the `.hg` extension. Run files as you would with any other interpreted language.
|
||||
Solstice files use the `.sols` extension. Run files as you would with any other interpreted language.
|
||||
|
||||
## Using High Ground
|
||||
## Docs
|
||||
|
||||
### Types
|
||||
|
||||
* `int`: Ground int (64 bit integer) eg 3, 7, 31432
|
||||
* `double`: Ground double (Double precision floating point) eg 3.141, 2.7
|
||||
* `string`: Ground string (char*) eg "Hello, World"
|
||||
* `char`: Ground char (char) eg 'a'
|
||||
* `bool`: Ground bool (either true or false)
|
||||
|
||||
### Printing
|
||||
|
||||
Prefix an expression with `puts` to print it to the console.
|
||||
|
||||
```
|
||||
puts "Hello, world!"
|
||||
puts 3.141
|
||||
puts 7
|
||||
puts 'a'
|
||||
puts true
|
||||
```
|
||||
|
||||
### Math
|
||||
|
||||
Add numbers with `+` (more operations coming soon)
|
||||
|
||||
```
|
||||
puts 1 + 1
|
||||
puts 3.14 + 2.7
|
||||
puts 532 + 314 + 89432
|
||||
```
|
||||
Docs are avaliable at https://sols.dev/docs/
|
||||
14
chookspace/index.html
Normal file
14
chookspace/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Redirecting to sols.dev</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to sols.dev, if that doesn't work <a href="https://sols.dev">click here</a>.</p>
|
||||
<script>
|
||||
window.location.href = "https://sols.dev";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
15
libs/conversions.sols
Normal file
15
libs/conversions.sols
Normal file
@@ -0,0 +1,15 @@
|
||||
def stringToInt(string in) int {
|
||||
result = 0
|
||||
ground {
|
||||
stoi $in &result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
def intToString(int in) string {
|
||||
result = ""
|
||||
ground {
|
||||
tostring $in &result
|
||||
}
|
||||
return result
|
||||
}
|
||||
6
libs/file.sols
Normal file
6
libs/file.sols
Normal file
@@ -0,0 +1,6 @@
|
||||
def file_Read(string file) string {}
|
||||
def file_Write(string file, string content) bool {}
|
||||
|
||||
ground {
|
||||
extern "fileio"
|
||||
}
|
||||
23
libs/io.sols
Normal file
23
libs/io.sols
Normal file
@@ -0,0 +1,23 @@
|
||||
def input(string msg) string {
|
||||
retval = ""
|
||||
ground {
|
||||
print $msg
|
||||
input &retval
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
def print(string msg) string {
|
||||
ground {
|
||||
print $msg
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
def println(string msg) string {
|
||||
ground {
|
||||
println $msg
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
12
libs/request.sols
Normal file
12
libs/request.sols
Normal file
@@ -0,0 +1,12 @@
|
||||
def request_Get(string url) string {}
|
||||
def request_Post(string url, string data) string {}
|
||||
def ws_Connect(string url) int {}
|
||||
def ws_Send(int connId, string data) int {}
|
||||
def ws_SendBinary(int connId, string data) int {}
|
||||
def ws_Receive(int connId) string {}
|
||||
def ws_ReceiveTimeout(int connId, int timeout) string {}
|
||||
def ws_Close(int connId) bool {}
|
||||
|
||||
ground {
|
||||
extern "request"
|
||||
}
|
||||
43
libs/unistd.sols
Normal file
43
libs/unistd.sols
Normal file
@@ -0,0 +1,43 @@
|
||||
def unistd_Crypt(string key, string value) string {}
|
||||
def unistd_GetHostId() string {}
|
||||
def unistd_SetHotId(int hostid) int {}
|
||||
def unistd_GetHostname() string {}
|
||||
def unistd_SetHostname(string name) int {}
|
||||
|
||||
def unistd_Alarm(int seconds) int {}
|
||||
def unistd_Pause() int {}
|
||||
|
||||
unistd_F_OK = 0
|
||||
unistd_R_OK = 0
|
||||
unistd_W_OK = 0
|
||||
unistd_X_OK = 0
|
||||
|
||||
def unistd_Access(string path, int mode) int {}
|
||||
def unistd_Chdir(string path) int {}
|
||||
def unistd_Chown(string path, int owner, int group) int {}
|
||||
def unistd_Link(string oldpath, string newpath) int {}
|
||||
def unistd_Rmdir(string path) int {}
|
||||
def unistd_Symlink(string target, string linkpath) int {}
|
||||
|
||||
def unistd_Exit(int status) int {}
|
||||
def unistd_Fork() int {}
|
||||
def unistd_GetPid() int {}
|
||||
def unistd_GetPPid() int {}
|
||||
def unistd_GetSid(int pid) int {}
|
||||
def unistd_Nice(int inc) int {}
|
||||
def unistd_SetSid() int {}
|
||||
def unistd_Sleep(int seconds) int {}
|
||||
|
||||
def unistd_GetGid() int {}
|
||||
def unistd_GetEGid() int {}
|
||||
def unistd_GetUid() int {}
|
||||
def unistd_GetEUid() int {}
|
||||
def unistd_GetLogin() string {}
|
||||
def unistd_SetEUid(int euid) int {}
|
||||
def unistd_SetEGid(int egid) int {}
|
||||
def unistd_SetREUid(int ruid, int euid) int {}
|
||||
def unistd_SetREGid(int rgid, int egid) int {}
|
||||
|
||||
ground {
|
||||
extern "unistd"
|
||||
}
|
||||
BIN
logo/solstice.png
Normal file
BIN
logo/solstice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
78
logo/solstice.svg
Normal file
78
logo/solstice.svg
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
sodipodi:docname="solstice.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="1.8101934"
|
||||
inkscape:cx="341.39999"
|
||||
inkscape:cy="633.35776"
|
||||
inkscape:window-width="1908"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="linearGradient8"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#64ffe1;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop8" />
|
||||
<stop
|
||||
style="stop-color:#a3b9f5;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#d1b8fb;stop-opacity:1;"
|
||||
offset="0.75"
|
||||
id="stop11" />
|
||||
<stop
|
||||
style="stop-color:#f3cdff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient8"
|
||||
id="linearGradient9"
|
||||
x1="-42.253399"
|
||||
y1="135.74071"
|
||||
x2="-41.225731"
|
||||
y2="239.96782"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.73239966,-0.77274564,0.76516532,0.73965537,-4.0932457,-8.6853091)" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
id="path1"
|
||||
style="fill:url(#linearGradient9);fill-opacity:1;stroke:#ffffff;stroke-width:0.281629;stroke-opacity:0"
|
||||
d="m 100.38267,124.7767 a 31.775753,32.090549 0 0 0 -22.257004,9.893 31.775753,32.090549 0 0 0 0.979215,45.36846 l -0.0038,0.004 45.917939,44.38672 43.95132,-46.37229 -45.91795,-44.38673 -0.004,0.004 a 31.775753,32.090549 0 0 0 -22.66587,-8.8969 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
BIN
src/lexer/.DS_Store
vendored
Normal file
BIN
src/lexer/.DS_Store
vendored
Normal file
Binary file not shown.
97
src/lexer/lexer.sols
Normal file
97
src/lexer/lexer.sols
Normal file
@@ -0,0 +1,97 @@
|
||||
use collections
|
||||
use string
|
||||
|
||||
//
|
||||
// Token type enum.
|
||||
//
|
||||
// Each token can be one of these types.
|
||||
//
|
||||
enum SolsToken {
|
||||
Identifier, Literal, Type,
|
||||
|
||||
Dot, OpenCurly, CloseCurly, OpenParen, CloseParen, Comma,
|
||||
|
||||
OpAdd, OpSub, OpMul, OpDiv, OpAddTo, OpSubTo, OpMulTo, OpDivTo, OpIncrement, OpDecrement, OpSet,
|
||||
OpGreater, OpLesser, OpEqual, OpInequal, OpEqGreater, OpEqLesser,
|
||||
|
||||
KwDef, KwLambda, KwReturn, KwUse, KwStruct, KwEnum, KwConstructor,
|
||||
KwDestructor, KwDuplicator, KwPrivate, KwProtected, KwPuts, KwIf,
|
||||
KwWhile, KwNew, KwGround,
|
||||
|
||||
LineEnd,
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Token type map.
|
||||
//
|
||||
// If a token matches one of the strings in this hashmap,
|
||||
// its type gets set to the token type for that string.
|
||||
//
|
||||
KEYWORDS = Hashmap()
|
||||
KEYWORDS.set("puts", SolsToken.KwPuts)
|
||||
KEYWORDS.set("if", SolsToken.KwIf)
|
||||
KEYWORDS.set("while", SolsToken.KwWhile)
|
||||
KEYWORDS.set("def", SolsToken.KwDef)
|
||||
KEYWORDS.set("lambda", SolsToken.KwLambda)
|
||||
KEYWORDS.set("return", SolsToken.KwReturn)
|
||||
KEYWORDS.set("use", SolsToken.KwUse)
|
||||
KEYWORDS.set("struct", SolsToken.KwStruct)
|
||||
KEYWORDS.set("enum", SolsToken.KwEnum)
|
||||
KEYWORDS.set("constructor", SolsToken.KwConstructor)
|
||||
KEYWORDS.set("destructor", SolsToken.KwDestructor)
|
||||
KEYWORDS.set("duplicator", SolsToken.KwDuplicator)
|
||||
KEYWORDS.set("private", SolsToken.KwPrivate)
|
||||
KEYWORDS.set("protected", SolsToken.KwProtected)
|
||||
KEYWORDS.set("ground", SolsToken.KwGround)
|
||||
KEYWORDS.set("new", SolsToken.KwNew)
|
||||
KEYWORDS.set("{", SolsToken.OpenCurly)
|
||||
KEYWORDS.set("}", SolsToken.CloseCurly)
|
||||
KEYWORDS.set("(", SolsToken.OpenParen)
|
||||
KEYWORDS.set(")", SolsToken.CloseParen)
|
||||
KEYWORDS.set("+", SolsToken.OpAdd)
|
||||
KEYWORDS.set("-", SolsToken.OpSub)
|
||||
KEYWORDS.set("*", SolsToken.OpMul)
|
||||
KEYWORDS.set("/", SolsToken.OpDiv)
|
||||
KEYWORDS.set("=", SolsToken.OpSet)
|
||||
KEYWORDS.set("+=", SolsToken.OpAddTo)
|
||||
KEYWORDS.set("-=", SolsToken.OpSubTo)
|
||||
KEYWORDS.set("*=", SolsToken.OpMulTo)
|
||||
KEYWORDS.set("/=", SolsToken.OpDivTo)
|
||||
KEYWORDS.set("++", SolsToken.OpIncrement)
|
||||
KEYWORDS.set("--", SolsToken.OpDecrement)
|
||||
KEYWORDS.set("==", SolsToken.OpEqual)
|
||||
KEYWORDS.set("!=", SolsToken.OpInequal)
|
||||
KEYWORDS.set(">", SolsToken.OpGreater)
|
||||
KEYWORDS.set("<", SolsToken.OpLesser)
|
||||
KEYWORDS.set(">=", SolsToken.OpEqGreater)
|
||||
KEYWORDS.set("<=", SolsToken.OpEqLesser)
|
||||
KEYWORDS.set("\n", SolsToken.LineEnd)
|
||||
KEYWORDS.set(";", SolsToken.LineEnd)
|
||||
KEYWORDS.set(",", SolsToken.Comma)
|
||||
|
||||
struct SolsLexer {
|
||||
sourceCode = "x = 123"
|
||||
current = 0
|
||||
|
||||
private def getTokenType(string input) SolsToken {
|
||||
return KEYWORDS.get(input)
|
||||
}
|
||||
|
||||
def lex() {
|
||||
inString = false
|
||||
|
||||
lineNum = 1
|
||||
lineStart = 0
|
||||
currentLine = ""
|
||||
|
||||
while lineStart < string_Length() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
lexer = new SolsLexer
|
||||
puts lexer.getTokenType("if")
|
||||
563
src/main.cpp
563
src/main.cpp
@@ -1,563 +0,0 @@
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <groundvm.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#define parseOneToken(token) Parser({token.value()}).parse().children[0]
|
||||
|
||||
namespace HighGround {
|
||||
|
||||
int tmpIdIterator = 0;
|
||||
|
||||
namespace Parser {
|
||||
|
||||
enum class HGNodeType {
|
||||
Add, Subtract, Equal, Set, While, If, Value, Identifier, None, Root, CodeBlock, CodeBlockStart, CodeBlockEnd, Puts
|
||||
};
|
||||
|
||||
enum class HGDataType {
|
||||
Int, String, Double, Bool, Char, None
|
||||
};
|
||||
|
||||
class HGNode;
|
||||
|
||||
class HGGroundCodeBlock {
|
||||
public:
|
||||
std::vector<GroundInstruction> code;
|
||||
HGGroundCodeBlock() = default;
|
||||
};
|
||||
|
||||
class HGData {
|
||||
typedef std::variant<int64_t, std::string, double, bool, char> varData;
|
||||
varData data;
|
||||
public:
|
||||
HGDataType type = HGDataType::Int;
|
||||
HGData() = default;
|
||||
HGData(int64_t in) : data(in), type(HGDataType::Int) {}
|
||||
HGData(double in) : data(in), type(HGDataType::Double) {}
|
||||
HGData(std::string in) : data(in), type(HGDataType::String) {}
|
||||
HGData(char in) : data(in), type(HGDataType::Char) {}
|
||||
HGData(bool in) : data(in), type(HGDataType::Bool) {}
|
||||
std::optional<int64_t> getInt() {
|
||||
if (type == HGDataType::Int) {
|
||||
return std::get<int64_t>(data);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::optional<double> getDouble() {
|
||||
if (type == HGDataType::Double) {
|
||||
return std::get<double>(data);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::optional<std::string> getString() {
|
||||
if (type == HGDataType::String) {
|
||||
return std::get<std::string>(data);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::optional<char> getChar() {
|
||||
if (type == HGDataType::Char) {
|
||||
return std::get<char>(data);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::optional<bool> getBool() {
|
||||
if (type == HGDataType::Bool) {
|
||||
return std::get<bool>(data);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class HGNode {
|
||||
HGNodeType nodeType = HGNodeType::None;
|
||||
HGData data;
|
||||
public:
|
||||
std::vector<HGNode> children;
|
||||
std::string outputId;
|
||||
HGNode(HGNodeType nodeType) : nodeType(nodeType) {}
|
||||
HGNode(HGNodeType nodeType, HGData data) : nodeType(nodeType), data(data) {}
|
||||
HGNode() = default;
|
||||
void addNode(HGNode in) {
|
||||
children.push_back(in);
|
||||
}
|
||||
void setValue(HGData in) {
|
||||
data = in;
|
||||
}
|
||||
const std::vector<HGGroundCodeBlock> generateCode() {
|
||||
std::vector<HGGroundCodeBlock> code;
|
||||
for (auto& child : children) {
|
||||
auto childCode = child.generateCode();
|
||||
code.insert(code.end(), childCode.begin(), childCode.end());
|
||||
}
|
||||
switch (nodeType) {
|
||||
case HGNodeType::Value: {
|
||||
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
||||
HGGroundCodeBlock codeBlock;
|
||||
GroundInstruction gi = groundCreateInstruction(SET);
|
||||
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
|
||||
switch (data.type) {
|
||||
case HGDataType::Int: {
|
||||
auto dataopt = data.getInt();
|
||||
if (dataopt) {
|
||||
groundAddValueToInstruction(&gi, groundCreateValue(INT, dataopt.value()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGDataType::Double: {
|
||||
auto dataopt = data.getDouble();
|
||||
if (dataopt) {
|
||||
groundAddValueToInstruction(&gi, groundCreateValue(DOUBLE, dataopt.value()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGDataType::String: {
|
||||
auto dataopt = data.getString();
|
||||
if (dataopt) {
|
||||
groundAddValueToInstruction(&gi, groundCreateValue(STRING, dataopt.value().c_str()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGDataType::Char: {
|
||||
auto dataopt = data.getChar();
|
||||
if (dataopt) {
|
||||
groundAddValueToInstruction(&gi, groundCreateValue(CHAR, dataopt.value()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGDataType::Bool: {
|
||||
auto dataopt = data.getBool();
|
||||
if (dataopt) {
|
||||
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, dataopt.value()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
codeBlock.code.push_back(gi);
|
||||
code.push_back(codeBlock);
|
||||
break;
|
||||
}
|
||||
case HGNodeType::Add: {
|
||||
HGGroundCodeBlock codeBlock;
|
||||
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
||||
GroundInstruction gi = groundCreateInstruction(ADD);
|
||||
if (children.size() < 2) {
|
||||
std::cout << "Need more stuff to add\n";
|
||||
}
|
||||
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
|
||||
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
|
||||
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
|
||||
codeBlock.code.push_back(gi);
|
||||
code.push_back(codeBlock);
|
||||
break;
|
||||
}
|
||||
case HGNodeType::Puts: {
|
||||
HGGroundCodeBlock codeBlock;
|
||||
GroundInstruction gi = groundCreateInstruction(PRINTLN);
|
||||
if (children.size() < 1) {
|
||||
std::cout << "Need more stuff to puts\n";
|
||||
}
|
||||
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
|
||||
codeBlock.code.push_back(gi);
|
||||
code.push_back(codeBlock);
|
||||
break;
|
||||
}
|
||||
default: {}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Parser {
|
||||
std::vector<std::string> tokensToParse;
|
||||
size_t current;
|
||||
size_t size;
|
||||
|
||||
std::optional<std::string> peek(int ahead = 1) {
|
||||
if (current + ahead < size) {
|
||||
return tokensToParse[current + ahead];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> consume() {
|
||||
if (current < size) {
|
||||
return tokensToParse[current++];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool isInt(std::string in) {
|
||||
for (const char& c : in) {
|
||||
if (!std::isdigit(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isDouble(std::string in) {
|
||||
bool foundDot = false;
|
||||
for (const char& c : in) {
|
||||
if (!std::isdigit(c)) {
|
||||
if (!foundDot && c == '.') {
|
||||
foundDot = true;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isString(std::string in) {
|
||||
if (in.size() > 1 && in[0] == '"' && in.back() == '"') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool isChar(std::string in) {
|
||||
if (in.size() == 3 && in[0] == '\'' && in.back() == '\'') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool isBool(std::string in) {
|
||||
if (in == "true" || in == "false") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HGDataType getDataType(std::string in) {
|
||||
if (isInt(in)) {
|
||||
return HGDataType::Int;
|
||||
}
|
||||
if (isDouble(in)) {
|
||||
return HGDataType::Double;
|
||||
}
|
||||
if (isString(in)) {
|
||||
return HGDataType::String;
|
||||
}
|
||||
if (isChar(in)) {
|
||||
return HGDataType::Char;
|
||||
}
|
||||
if (isBool(in)) {
|
||||
return HGDataType::Bool;
|
||||
}
|
||||
return HGDataType::None;
|
||||
}
|
||||
|
||||
HGNodeType getNodeType(std::string in) {
|
||||
if (getDataType(in) != HGDataType::None) {
|
||||
return HGNodeType::Value;
|
||||
}
|
||||
if (in == "+") {
|
||||
return HGNodeType::Add;
|
||||
}
|
||||
if (in == "puts") {
|
||||
return HGNodeType::Puts;
|
||||
}
|
||||
if (in == "if") {
|
||||
return HGNodeType::If;
|
||||
}
|
||||
if (in == "{") {
|
||||
return HGNodeType::CodeBlockStart;
|
||||
}
|
||||
if (in == "}") {
|
||||
return HGNodeType::CodeBlockEnd;
|
||||
}
|
||||
return HGNodeType::None;
|
||||
}
|
||||
|
||||
public:
|
||||
Parser(std::vector<std::string> in) : tokensToParse(in) {}
|
||||
|
||||
HGNode parse() {
|
||||
current = 0;
|
||||
size = tokensToParse.size();
|
||||
HGNode rootNode(HGNodeType::Root);
|
||||
while (auto tokenopt = consume()) {
|
||||
std::string token = tokenopt.value();
|
||||
switch (getNodeType(token)) {
|
||||
case HGNodeType::Value: {
|
||||
switch (getDataType(token)) {
|
||||
case HGDataType::Int: {
|
||||
HGNode intNode(HGNodeType::Value);
|
||||
intNode.setValue((int64_t) std::stoll(token));
|
||||
rootNode.addNode(intNode);
|
||||
break;
|
||||
}
|
||||
case HGDataType::Double: {
|
||||
HGNode doubleNode(HGNodeType::Value);
|
||||
doubleNode.setValue(std::stod(token));
|
||||
rootNode.addNode(doubleNode);
|
||||
break;
|
||||
}
|
||||
case HGDataType::String: {
|
||||
HGNode stringNode(HGNodeType::Value);
|
||||
stringNode.setValue(token.substr(1, token.size() - 2));
|
||||
rootNode.addNode(stringNode);
|
||||
break;
|
||||
}
|
||||
case HGDataType::Char: {
|
||||
HGNode charNode(HGNodeType::Value);
|
||||
charNode.setValue(token[1]);
|
||||
rootNode.addNode(charNode);
|
||||
break;
|
||||
}
|
||||
case HGDataType::Bool: {
|
||||
HGNode boolNode(HGNodeType::Value);
|
||||
boolNode.setValue(token == "true");
|
||||
rootNode.addNode(boolNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGNodeType::Add: {
|
||||
HGNode addNode(HGNodeType::Add);
|
||||
addNode.addNode(rootNode.children.back());
|
||||
rootNode.children.pop_back();
|
||||
auto tokenopt = consume();
|
||||
if (tokenopt) {
|
||||
addNode.addNode(parseOneToken(tokenopt));
|
||||
} else {
|
||||
std::cout << "FEED ME MORE TOKENS\n";
|
||||
exit(1);
|
||||
}
|
||||
rootNode.addNode(addNode);
|
||||
break;
|
||||
}
|
||||
case HGNodeType::Puts: {
|
||||
HGNode putsNode(HGNodeType::Puts);
|
||||
std::vector<std::string> tokens;
|
||||
while (auto tokenopt = consume()) {
|
||||
if (tokenopt.value() == "\n") {
|
||||
break;
|
||||
}
|
||||
tokens.push_back(tokenopt.value());
|
||||
}
|
||||
auto children = Parser(tokens).parse();
|
||||
for (auto& child : children.children) {
|
||||
putsNode.addNode(child);
|
||||
}
|
||||
rootNode.addNode(putsNode);
|
||||
break;
|
||||
}
|
||||
case HGNodeType::If: {
|
||||
HGNode ifNode(HGNodeType::If);
|
||||
std::vector<std::string> tokens;
|
||||
while (auto tokenopt = consume()) {
|
||||
if (tokenopt.value() == "\n") {
|
||||
break;
|
||||
}
|
||||
tokens.push_back(tokenopt.value());
|
||||
}
|
||||
auto children = Parser(tokens).parse();
|
||||
if (children.children.size() != 1) {
|
||||
std::cout << "Too many or too little conditions for if\n";
|
||||
exit(1);
|
||||
}
|
||||
ifNode.addNode(children.children[0]);
|
||||
tokens.clear();
|
||||
size_t brackets = 1;
|
||||
auto tokenopt = consume();
|
||||
if (tokenopt) {
|
||||
if (tokenopt.value() == "{") {
|
||||
tokens.push_back(tokenopt.value());
|
||||
while (auto tokenopt = consume()) {
|
||||
tokens.push_back(tokenopt.value());
|
||||
if (tokenopt.value() == "{") {
|
||||
brackets++;
|
||||
}
|
||||
if (tokenopt.value() == "}") {
|
||||
brackets--;
|
||||
}
|
||||
if (brackets == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cout << "I want a code block\n";
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
std::cout << "FEED ME MORE TOKENSSSSS\n";
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HGNodeType::CodeBlockStart: {
|
||||
HGNode codeBlockNode(HGNodeType::CodeBlock);
|
||||
// WIP
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
};
|
||||
|
||||
GroundProgram assembleProgram(HGNode& rootNode) {
|
||||
GroundProgram gp = groundCreateProgram();
|
||||
auto code = rootNode.generateCode();
|
||||
for (int i = 0; i < code.size(); i++) {
|
||||
for (const auto& inst : code[i].code) {
|
||||
groundAddInstructionToProgram(&gp, inst);
|
||||
}
|
||||
}
|
||||
return gp;
|
||||
}
|
||||
|
||||
} // namespace Parser
|
||||
|
||||
class Lexer {
|
||||
std::string input;
|
||||
size_t size;
|
||||
size_t current;
|
||||
|
||||
std::optional<char> peek(int ahead = 1) {
|
||||
if (current + ahead < size) {
|
||||
return input[current + ahead];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<char> consume() {
|
||||
if (current < size) {
|
||||
return input[current++];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Lexer(std::string in) : input(in), size(in.size()) {};
|
||||
std::vector<std::string> lex() {
|
||||
current = 0;
|
||||
std::vector<std::string> tokens;
|
||||
std::string buf;
|
||||
while (auto copt = consume()) {
|
||||
char c = copt.value();
|
||||
switch (c) {
|
||||
// tokens which are not followed by anything
|
||||
case '\n':
|
||||
case '(':
|
||||
case ')':
|
||||
case '}':
|
||||
{
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
tokens.push_back(std::string(1, c));
|
||||
break;
|
||||
}
|
||||
// tokens which may be followed by either themselves
|
||||
// or an equals sign
|
||||
case '+':
|
||||
case '-':
|
||||
{
|
||||
std::string newToken(1, c);
|
||||
auto tokenopt = peek();
|
||||
if (tokenopt) {
|
||||
char token = tokenopt.value();
|
||||
if (token == c || token == '=') {
|
||||
newToken += token;
|
||||
consume();
|
||||
}
|
||||
}
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
tokens.push_back(newToken);
|
||||
break;
|
||||
}
|
||||
// tokens which may be followed by an equals sign
|
||||
case '*':
|
||||
case '/':
|
||||
case '=':
|
||||
{
|
||||
std::string newToken(1, c);
|
||||
auto tokenopt = peek();
|
||||
if (tokenopt) {
|
||||
char token = tokenopt.value();
|
||||
if (token == '=') {
|
||||
newToken += token;
|
||||
consume();
|
||||
}
|
||||
}
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
tokens.push_back(newToken);
|
||||
break;
|
||||
}
|
||||
// tokens which need a newline inserted for them
|
||||
case '{':
|
||||
{
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
tokens.push_back(std::string(1, c));
|
||||
tokens.push_back("\n");
|
||||
}
|
||||
// tokens which do not need to be included
|
||||
case ' ':
|
||||
{
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
buf += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!buf.empty()) {
|
||||
tokens.push_back(buf);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace HighGround
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage: " << argv[0] << " (file)\n";
|
||||
exit(1);
|
||||
}
|
||||
std::ifstream file(argv[1]);
|
||||
std::ostringstream ss;
|
||||
ss << file.rdbuf();
|
||||
auto lexed = HighGround::Lexer(ss.str()).lex();
|
||||
auto parsed = HighGround::Parser::Parser(lexed).parse();
|
||||
GroundProgram program = HighGround::Parser::assembleProgram(parsed);
|
||||
groundRunProgram(&program);
|
||||
}
|
||||
0
src/main.sols
Normal file
0
src/main.sols
Normal file
9
tests/closure.sols
Normal file
9
tests/closure.sols
Normal file
@@ -0,0 +1,9 @@
|
||||
def createClosure(int x) fun(int) int {
|
||||
return lambda(int y) int {
|
||||
return x + y
|
||||
}
|
||||
}
|
||||
|
||||
myVar = createClosure(5)
|
||||
|
||||
puts myVar(3)
|
||||
55
tests/compare.sols
Normal file
55
tests/compare.sols
Normal file
@@ -0,0 +1,55 @@
|
||||
if 1 == 1 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 1 == 2 {
|
||||
puts "not working"
|
||||
}
|
||||
|
||||
if 1 != 2 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 1 != 1 {
|
||||
puts "not working"
|
||||
}
|
||||
|
||||
if 2 > 1 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 1 > 2 {
|
||||
puts "not working"
|
||||
}
|
||||
|
||||
if 1 < 2 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 2 < 1 {
|
||||
puts "not working"
|
||||
}
|
||||
|
||||
if 2 >= 2 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 2 >= 1 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 2 >= 3 {
|
||||
puts "not working"
|
||||
}
|
||||
|
||||
if 2 <= 2 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 2 <= 3 {
|
||||
puts "working"
|
||||
}
|
||||
|
||||
if 3 <= 2 {
|
||||
puts "not working"
|
||||
}
|
||||
11
tests/convert.sols
Normal file
11
tests/convert.sols
Normal file
@@ -0,0 +1,11 @@
|
||||
use conversions
|
||||
use io
|
||||
|
||||
myString = "312"
|
||||
myInt = 435
|
||||
|
||||
myNewString = intToString(myInt)
|
||||
myNewInt = stringToInt(myString)
|
||||
|
||||
println(myNewString)
|
||||
puts myNewInt
|
||||
6
tests/count.sols
Normal file
6
tests/count.sols
Normal file
@@ -0,0 +1,6 @@
|
||||
number = 0
|
||||
|
||||
while number != 10 {
|
||||
number = number + 1
|
||||
puts number
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
puts "dingus"
|
||||
puts 432
|
||||
puts 3.141
|
||||
puts 'c'
|
||||
puts true
|
||||
7
tests/data.sols
Normal file
7
tests/data.sols
Normal file
@@ -0,0 +1,7 @@
|
||||
puts "dingus"
|
||||
puts 432
|
||||
puts 3.141
|
||||
puts 'c'
|
||||
puts true
|
||||
|
||||
puts "now we have proper string lexing!!!!!11!!@!2!1@1@12!!!112!@"
|
||||
15
tests/fib.sols
Normal file
15
tests/fib.sols
Normal file
@@ -0,0 +1,15 @@
|
||||
a = 0
|
||||
b = 1
|
||||
n = 92
|
||||
|
||||
i = 0
|
||||
|
||||
while i != n {
|
||||
temp = a + b
|
||||
a = b
|
||||
b = temp
|
||||
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
puts a
|
||||
6
tests/function.sols
Normal file
6
tests/function.sols
Normal file
@@ -0,0 +1,6 @@
|
||||
def add(int a, int b) int {
|
||||
puts "testing"
|
||||
return 3
|
||||
}
|
||||
|
||||
puts add(1, 2)
|
||||
7
tests/if.sols
Normal file
7
tests/if.sols
Normal file
@@ -0,0 +1,7 @@
|
||||
if 1 == 1 {
|
||||
puts "huzzah"
|
||||
}
|
||||
|
||||
if 5 == 10 {
|
||||
puts "aww"
|
||||
}
|
||||
7
tests/inlineground.sols
Normal file
7
tests/inlineground.sols
Normal file
@@ -0,0 +1,7 @@
|
||||
result = 0
|
||||
ground {
|
||||
println "dingus"
|
||||
add 3 2 &result
|
||||
}
|
||||
|
||||
puts result
|
||||
15
tests/input.sols
Normal file
15
tests/input.sols
Normal file
@@ -0,0 +1,15 @@
|
||||
use io
|
||||
|
||||
accessNotGranted = true
|
||||
|
||||
while accessNotGranted {
|
||||
password = input("Password: ")
|
||||
if password == "dingus" {
|
||||
accessNotGranted = false
|
||||
}
|
||||
if password != "dingus" {
|
||||
puts "Incorrect password!"
|
||||
}
|
||||
}
|
||||
|
||||
puts "Welcome!"
|
||||
@@ -1 +1,3 @@
|
||||
use io
|
||||
|
||||
println("dingus")
|
||||
3
tests/set.sols
Normal file
3
tests/set.sols
Normal file
@@ -0,0 +1,3 @@
|
||||
x = 5
|
||||
y = 10
|
||||
puts x + y
|
||||
32
tests/struct.sols
Normal file
32
tests/struct.sols
Normal file
@@ -0,0 +1,32 @@
|
||||
struct Person {
|
||||
protected name = ""
|
||||
private age = 0
|
||||
|
||||
def greet() string {
|
||||
return "Hello, " + self.name + "!"
|
||||
}
|
||||
|
||||
def dance() string {
|
||||
return "Dancing..."
|
||||
}
|
||||
|
||||
constructor(string name, int age) {
|
||||
self.name = name
|
||||
self.age = age
|
||||
}
|
||||
|
||||
destructor {
|
||||
// We don't need to do anything here.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
max = Person("Max", 16)
|
||||
|
||||
puts max
|
||||
puts max.greet()
|
||||
puts max.name
|
||||
// puts max.age (causes compile time error, age is private)
|
||||
// max.name = "Maximilian" (causes compile time error, name is protected)
|
||||
|
||||
max.dance()
|
||||
3
tests/while.sols
Normal file
3
tests/while.sols
Normal file
@@ -0,0 +1,3 @@
|
||||
while 1 == 1 {
|
||||
puts "yay infinite loop"
|
||||
}
|
||||
1
vim/ftdetect/solstice.vim
Normal file
1
vim/ftdetect/solstice.vim
Normal file
@@ -0,0 +1 @@
|
||||
au BufRead,BufNewFile *.sols setfiletype solstice
|
||||
45
vim/syntax/solstice.vim
Normal file
45
vim/syntax/solstice.vim
Normal file
@@ -0,0 +1,45 @@
|
||||
" Vim highlight file for Solstice (.sols)
|
||||
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
" Keywords
|
||||
syn keyword solsKeyword puts if while def lambda return use struct ground
|
||||
syn keyword solsBool true false
|
||||
|
||||
" Types
|
||||
syn keyword solsType int double string char bool fun template object
|
||||
|
||||
" Strings and chars
|
||||
syn region solsString start=/"/ skip=/\\"/ end=/"/
|
||||
syn region solsChar start=/'/ skip=/\\'/ end=/'/
|
||||
|
||||
" Numbers
|
||||
syn match solsFloat /\<[0-9]\+\.[0-9]*\>/
|
||||
syn match solsInt /\<[0-9]\+\>/
|
||||
|
||||
" Operators
|
||||
syn match solsOperator /+\|-\|\*\|\/\|=\|!\|>\|<\|+=\|-=\|\*=\|\/=\|++\|--\|==\|!=\|>=\|<=/
|
||||
|
||||
" Delimiters
|
||||
syn match solsDelimiter /[{}(),;]/
|
||||
|
||||
" Comments
|
||||
syn match solsComment /\/\/.*$/
|
||||
syn match solsComment /#.*$/
|
||||
|
||||
" Highlight links
|
||||
hi def link solsKeyword Keyword
|
||||
hi def link solsBool Boolean
|
||||
hi def link solsType Type
|
||||
hi def link solsString String
|
||||
hi def link solsChar Character
|
||||
hi def link solsFloat Float
|
||||
hi def link solsInt Number
|
||||
hi def link solsOperator Operator
|
||||
hi def link solsDelimiter Delimiter
|
||||
hi def link solsComment Comment
|
||||
|
||||
let b:current_syntax = "solstice"
|
||||
|
||||
Reference in New Issue
Block a user