Files
one/README.md

304 lines
6.9 KiB
Markdown

# One
One is a statically typed language inspired by C, V, and go.
The compiler is still in development, and may present issues when compiling One code.
Note that you need to have eitehr gcc or clang installed to compile One code, as the compiler
produces C code that later gets compiled to an executable.
---
## Syntax
One's syntax rules are meant to be easily understandable and, more importantly, never ambiguous.
---
### Variables
In One, variables are declared with the `let` keyword.
The syntax will look something like this
```
let x: int = 6;
```
You can also declare a constant using the `const` keyword instead.
```
const x: int = 9;
```
---
### Comments
Comments in One start with a # and end with another # or a newline
```
#this is a comment
let #also a comment# a: int = 9;
```
---
### Scopes
Like in most languages, variables in One are only limited to their scope.
You can access a variable from a deeper nested scope, but not the opposite:
```
let x: int = 5;
if 5 > 0 {
x = 2;
}
```
is valid code, while
```
if 3 < 10 {
let y: int = 288;
}
y = 10;
```
isn't valid, as the variable `y` cannot be access outside its scope.
You can also create scopes by wrapping statements in braces. This lets you declare
variables with the same name in different scopes, for example:
```
let x: int = 3
{
let y: real = 5.5;
print(y);
}
#y is now undefined again here
{
let y: real = 0.2;
print(y);
}
```
---
### Primitive Types
As of now, One has a total of 4 primitive types: `void`. `int`, `real`, `bool` and `string`.
There are no methods for types, but you can cast a variable to one of them with this syntax
```
let myreal: real = 1.5;
let myint: int = int(myreal);
```
Right now, strings are implemented as direct counterparts to `char*` in C, which is what they
get translated to during compilation. Comparisons and operations on strings are still work in progress
and quite buggy, but you are free to use string literals for prints or simple variable declarations with no issues.
Variables cannot be declared with type `void`.
The `string` type actually behaves similarly to how a class would. While using the variable directly
gives you access to the actual string (which in C corresponds to the `char*`), you can use `.len` to
get the length of the string. Note that `len` is an immutable member, so you cannot maually set it.
```
let mystring: string = "this is my string";
print(mystring, mystring.len)
```
produces this output:
```
this is my string 17
```
---
### References
One's counterpart to C's pointers are references, which behave the exact same way.
The main difference is in how you reference/dereference a variable. We all know C's
referencing and dereferencing operators cause some confusion when first learning the language,
and to prevent this, One has designated `ref` and `deref` keywords that are meant to be used like
functions. Here's an example:
```
let x: int = 6;
let ref_to_x: ref(int) = ref(x);
let y: int = deref(ref_to_x) # same as y = x
```
References to objects are again quite similar to C, with the only real difference being
the access to an object's members. in One, you an access members of an object or of a
reference to an object with the `.` notation. But you cannot access the members if the
reference nesting goes further. For example:
```
let u: User = User{17} #user has age 17
print(u.age) # outputs 17
let ref_to_u: ref(User) = ref(u)
print(ref_to_u.age) # outputs 17
let nested_ref: ref(ref(User)) = ref(ref_to_u)
print(nested_ref.age) # not valid
```
Right now, in error messages, it's likely you will still find references marked as `*`s, such as `int*`
---
### Functions
Functions in One are very similar to what you see in languages such as go.
You declare a function called `foo` which takes an `int` and returns a `bool` with the following syntax:
```
fn foo(myarg: int) bool {
return myarg < 10;
}
```
If a function is not expected to return anything, the return type must be `void`.
Calling a function looks like this:
```
let b: bool = foo(9);
```
---
### Classes
Right now, Classes in One are very similar to C structs. They are declared using the `class` keyword
followed by the class name and a block with a list of class members.
Defining a class User might look something like this:
```
class User {
age: int
name: string
mail_verified: bool
}
```
Creating an instance of a class is very simple, just write the name of the class
followed by braces and a list of initial values for the class members.
```
let myuser: User = User{17, "uan", false}
```
Class types can be used anywhere primitive types can, such as function arguments
or other classes' members.
Class members can be defined as immutable with the `immutable` keyword before the member name.
This is checked at compile time and prevents that member's value to be changed after instantiation.
For example, this code would trigger a parse error, `as u.id = 0` attempts to change an immutable
member's value.
```
class User {
age: int
name: string
mail_verified: bool
immutable id: int
}
fn change_values(u: User) {
u.age = 10;
u.name = "new name";
u.id = 0;
}
```
---
### Methods
Defining a method is very similar to declaring a function. You just have to add the name
of the class between parentheses before the function name.
```
fn (User) age() void {
this.age++
}
```
as you can see, a variable called `this` is automatically declared in methods and is always
of type `ref` of the class, in this case `ref(User)`
---
### Print
Printing is still a work in progress feature, but right now you can print any primitive and non-primitive type.
The 'print' built-in function accepts a variable number of arguments, and will print allf
of them separated by a space.
```
let x: int = 144;
print(x, 240);
```
produces this output:
```
144 240
```
class-type variables will be printed with special formatting which, if we takes
the User class and variable we defined earlier, will look like this.
```
User {
age: 17
name: uan
mail_verified: false
}
```
### Control Flow
Control flow in One isn't fully implemented yet, but it is already functional.
`if`, `else` and `elif` statements are fully implemented and are written like this:
```
let x: int = 17;
if x >= 100 {
print(x, "is greater than 100");
} elif x >= 10 {
print(x, "is greater than 10"):
} else {
print(x, "is less than 10");
}
```
`while` loops are very similar, and can be written like this:
```
let i: int = 0;
while i < 10 {
print(i);
i++;
}
```
### The main function
It is important that every One program has an entry point called `main`.
The 'main' function must always return `int` and does not accept any arguments.
```
fn main() int {
#my code here
}
```
It isn't necessary to explicitly insert a `return` statement in the main function.
Returning from the main function will exit the program with an exit code equal
to the returned integer.