mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
fixed examples, fixed bug due to VType changes
This commit is contained in:
parent
d94f727eaa
commit
3032d3c115
@ -9,7 +9,7 @@ fn random(min int max int) {
|
|||||||
}
|
}
|
||||||
fn rnd() {
|
fn rnd() {
|
||||||
r := random(5 15)
|
r := random(5 15)
|
||||||
switch r {
|
switch! r {
|
||||||
int r r
|
int r r
|
||||||
[] [] 10
|
[] [] 10
|
||||||
}
|
}
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
lib mers_libs/gui
|
|
||||||
|
|
||||||
base = gui_init()
|
|
||||||
column = base.gui_add(Column: [])
|
|
||||||
|
|
||||||
text = column.gui_add(Text: "Welcome to MERS GUI!")
|
|
||||||
|
|
||||||
button = column.gui_add(Button: "This is a button.")
|
|
||||||
second_button = column.gui_add(Button: "This is a second button.")
|
|
||||||
|
|
||||||
text_state = -2
|
|
||||||
second_text = column.gui_add(Text: "press the button above to remove this text!")
|
|
||||||
|
|
||||||
loop {
|
|
||||||
for event gui_updates() {
|
|
||||||
switch! event {
|
|
||||||
ButtonPressed([int ...]) {
|
|
||||||
e = event.noenum()
|
|
||||||
match e {
|
|
||||||
&e.eq(&button) println("First button pressed")
|
|
||||||
&e.eq(&second_button) {
|
|
||||||
// don't match on text_state because we need to change the original from inside the match statement
|
|
||||||
state = text_state
|
|
||||||
match state {
|
|
||||||
// the first, third, fifth, ... time the button is pressed: remove the text
|
|
||||||
text_state.mod(2).eq(0) {
|
|
||||||
if text_state.eq(-2) {
|
|
||||||
// the first time the button is pressed
|
|
||||||
text_state = 0
|
|
||||||
set_title("keep pressing the button!")
|
|
||||||
}
|
|
||||||
second_text.gui_remove()
|
|
||||||
}
|
|
||||||
// the 2nd, 4th, 6th, ... time the button is pressed: add the text back
|
|
||||||
text_state.eq(1) second_text = column.gui_add(Text: "i'm back!")
|
|
||||||
text_state.eq(3) second_text = column.gui_add(Text: "you can't fully get rid of me!")
|
|
||||||
true {
|
|
||||||
second_text = column.gui_add(Text: "i always come back")
|
|
||||||
// restart (set text_state to 0)
|
|
||||||
text_state = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text_state = text_state.add(1)
|
|
||||||
}
|
|
||||||
true println("A different button was pressed (unreachable)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[]
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
lib mers_libs/http_requests
|
|
||||||
|
|
||||||
t = thread(() {
|
|
||||||
// because this downloads for so long, the println() will appear after the other one.
|
|
||||||
http_get("https:\//raw.githubusercontent.com/dwyl/english-words/master/words.txt").assume_no_enum()
|
|
||||||
println("got words from word list!")
|
|
||||||
})
|
|
||||||
|
|
||||||
sleep(0.1)
|
|
||||||
|
|
||||||
// this will finish before the thread does.
|
|
||||||
http_get("https:\//github.com/").assume_no_enum()
|
|
||||||
println("got github start page as html")
|
|
||||||
|
|
||||||
t.await()
|
|
||||||
|
|
||||||
http_get("not a url").debug()
|
|
@ -1,4 +1,4 @@
|
|||||||
fn map_string_to_int(list [string ...] func fn((string int))) {
|
fn map_string_to_int(list [string ...], func fn((string) int)) {
|
||||||
// return a function that can be used as an iterator
|
// return a function that can be used as an iterator
|
||||||
() {
|
() {
|
||||||
// this function will be called by the for loop
|
// this function will be called by the for loop
|
||||||
@ -36,4 +36,4 @@ fn square_numbers() {
|
|||||||
for n square_numbers() {
|
for n square_numbers() {
|
||||||
println(n.to_string())
|
println(n.to_string())
|
||||||
n >= 100
|
n >= 100
|
||||||
}
|
}
|
@ -1,74 +0,0 @@
|
|||||||
lib mers_libs/gui
|
|
||||||
|
|
||||||
// GUI for xrandr, because arandr doesn't let me change the framerates.
|
|
||||||
// [ WIP ]
|
|
||||||
|
|
||||||
base = gui_init()
|
|
||||||
|
|
||||||
set_title("MersRandr")
|
|
||||||
|
|
||||||
randr_output = run_command("xrandr")
|
|
||||||
|
|
||||||
switch! randr_output {
|
|
||||||
Err(string) {
|
|
||||||
println(randr_output.noenum())
|
|
||||||
}
|
|
||||||
[[]/int string string] {
|
|
||||||
lines = randr_output.1.regex(".*")
|
|
||||||
screen_name = ""
|
|
||||||
screen_resolutions = [["" ["" ...]] ...]
|
|
||||||
screens = [
|
|
||||||
[
|
|
||||||
screen_name
|
|
||||||
screen_resolutions
|
|
||||||
]
|
|
||||||
...]
|
|
||||||
&screen_resolutions.pop()
|
|
||||||
&screens.pop()
|
|
||||||
for line lines {
|
|
||||||
if line.starts_with("Screen ") {
|
|
||||||
// ignore
|
|
||||||
} else if line.starts_with(" ") {
|
|
||||||
// split at spaces (and ignore +*)
|
|
||||||
refresh_rates = line.regex("[^ +\\*]+").assume_no_enum()
|
|
||||||
resolution = &refresh_rates.remove(0).assume1()
|
|
||||||
print("{0} ::".format(resolution))
|
|
||||||
for rate refresh_rates {
|
|
||||||
print(" \"{0}\"".format(rate))
|
|
||||||
}
|
|
||||||
&screen_resolutions.push([resolution refresh_rates])
|
|
||||||
println("")
|
|
||||||
} else {
|
|
||||||
index = line.index_of(" ")
|
|
||||||
switch! index {
|
|
||||||
int {
|
|
||||||
if not(screen_name.len().eq(0)) {
|
|
||||||
&screens.push([screen_name screen_resolutions])
|
|
||||||
}
|
|
||||||
screen_resolutions = [ ...]
|
|
||||||
screen_name = line.substring(0 index)
|
|
||||||
println("> \"{0}\"".format(screen_name))
|
|
||||||
}
|
|
||||||
[] {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if not(screen_name.len().eq(0)) {
|
|
||||||
&screens.push([screen_name screen_resolutions])
|
|
||||||
}
|
|
||||||
for screen screens {
|
|
||||||
println(screen.0)
|
|
||||||
gui_screen = base.gui_add(Row: [])
|
|
||||||
gui_name = gui_screen.gui_add(Text: screen.0)
|
|
||||||
for res screen.1 {
|
|
||||||
gui_resolution = gui_screen.gui_add(Button: res.0)
|
|
||||||
print(" ")
|
|
||||||
println(res.0)
|
|
||||||
for rate res.1 {
|
|
||||||
print(" ")
|
|
||||||
println(rate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,205 +0,0 @@
|
|||||||
lib mers_libs/http_requests
|
|
||||||
lib mers_libs/gui
|
|
||||||
|
|
||||||
// MusicDB is a private project of mine.
|
|
||||||
// Basically, a SBC is hooked up to some speakers.
|
|
||||||
// It has a database of my songs and can play them.
|
|
||||||
// It can be controlled through HTTP requests, such as
|
|
||||||
// p- to stop
|
|
||||||
// p+ to play
|
|
||||||
// qi to get the queue index / playback position
|
|
||||||
// l to list all the songs
|
|
||||||
// ql or qL to list the queue
|
|
||||||
// ...
|
|
||||||
// this mers program should work as a very simple gui to remotely control
|
|
||||||
// the playback of songs. It should be able to add/remove songs to/from the queue,
|
|
||||||
// to start/stop playback, and to display some information about the current song.
|
|
||||||
|
|
||||||
// the url used to connect to the SBC and use the HTTP api
|
|
||||||
api_url = "http:\//192.168.2.103:26315/api/raw?"
|
|
||||||
|
|
||||||
// start the GUI
|
|
||||||
base = gui_init()
|
|
||||||
set_title("Mers MusicDB Remote")
|
|
||||||
|
|
||||||
playback_controls = base.gui_add(Row: [])
|
|
||||||
play_button = playback_controls.gui_add(Button: "Play")
|
|
||||||
stop_button = playback_controls.gui_add(Button: "Stop")
|
|
||||||
|
|
||||||
// these functions abstract away the api interactions
|
|
||||||
// because they aren't pretty.
|
|
||||||
// feel free to skip past this section and look at the gui code instead
|
|
||||||
fn make_api_request(to_api string) {
|
|
||||||
http_get(api_url.add(to_api))
|
|
||||||
}
|
|
||||||
fn get_queue_index() {
|
|
||||||
r = make_api_request("qi")
|
|
||||||
switch! r {
|
|
||||||
string {
|
|
||||||
r.regex("[0-9]").assume_no_enum().get(0).assume1().parse_int().assume1()
|
|
||||||
}
|
|
||||||
// return the error
|
|
||||||
Err(ErrBuildingRequest(string)/ErrGettingResponseText(string)) r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn get_db_contents() {
|
|
||||||
// list only 7 = 1 (title) + 2 (artist) + 4 (album)
|
|
||||||
r = make_api_request("lo7,")
|
|
||||||
switch! r {
|
|
||||||
string {
|
|
||||||
entries = r.regex("#.*:\n.*\n.*\n.*").assume_no_enum()
|
|
||||||
// initialize the list with a default value
|
|
||||||
// because mers doesnt know the inner type without it.
|
|
||||||
db = [[0 "title" "artist" "album"] ...]
|
|
||||||
&db.remove(0)
|
|
||||||
for entry entries {
|
|
||||||
lines = entry.regex(".*")
|
|
||||||
switch! lines {
|
|
||||||
[string ...] {
|
|
||||||
index_line = &lines.get(0).assume1()
|
|
||||||
index = index_line.substring(1 index_line.len().sub(1)).parse_int().assume1()
|
|
||||||
title = &lines.get(1).assume1().substring(1)
|
|
||||||
artist = &lines.get(2).assume1().substring(1)
|
|
||||||
album = &lines.get(3).assume1().substring(1)
|
|
||||||
&db.push([index title artist album])
|
|
||||||
}
|
|
||||||
Err(string) {
|
|
||||||
println("invalid response from server; 3u123128731289")
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db
|
|
||||||
}
|
|
||||||
Err(ErrBuildingRequest(string)/ErrGettingResponseText(string)) {
|
|
||||||
println("couldn't request db from server:")
|
|
||||||
print(" ")
|
|
||||||
println(r.to_string())
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn get_queue() {
|
|
||||||
r = make_api_request("ql")
|
|
||||||
switch! r {
|
|
||||||
string {
|
|
||||||
queue = [0 ...]
|
|
||||||
&queue.remove(0)
|
|
||||||
for index r.regex("[0-9]+[ \n]").assume_no_enum() {
|
|
||||||
&queue.push(index.substring(0 index.len().sub(1)).parse_int().assume1())
|
|
||||||
}
|
|
||||||
queue
|
|
||||||
}
|
|
||||||
Err(ErrBuildingRequest(string)/ErrGettingResponseText(string)) {
|
|
||||||
println("couldn't request queue from server:")
|
|
||||||
print(" ")
|
|
||||||
println(r.to_string())
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn play() {
|
|
||||||
r = make_api_request("p+")
|
|
||||||
switch! r {
|
|
||||||
// success! but nothing to return.
|
|
||||||
string []
|
|
||||||
// return the error
|
|
||||||
Err(ErrBuildingRequest(string)/ErrGettingResponseText(string)) r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn stop() {
|
|
||||||
r = make_api_request("p-")
|
|
||||||
switch! r {
|
|
||||||
// success! but nothing to return.
|
|
||||||
string []
|
|
||||||
// return the error
|
|
||||||
Err(ErrBuildingRequest(string)/ErrGettingResponseText(string)) r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn queue_song(song_id int) {
|
|
||||||
make_api_request("q+{0}".format(song_id.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch the database contents (a list of songs)
|
|
||||||
database = get_db_contents()
|
|
||||||
|
|
||||||
// this is where all the songs will be displayed.
|
|
||||||
songs_gui = base.gui_add(Row: [])
|
|
||||||
queue_list = songs_gui.gui_add(Column: [])
|
|
||||||
library = songs_gui.gui_add(Column: [])
|
|
||||||
|
|
||||||
limit = 0 // set to 0 to disable library length limit
|
|
||||||
for entry database {
|
|
||||||
// <SONG> by <ARTIST> on <ALBUM>
|
|
||||||
song = library.gui_add(Row: [])
|
|
||||||
song.gui_add(Button: entry.1)
|
|
||||||
song.gui_add(Text: "by {0} on {1}".format(entry.2 entry.3))
|
|
||||||
limit = limit.sub(1)
|
|
||||||
if limit.eq(0) [[]] else []
|
|
||||||
}
|
|
||||||
|
|
||||||
// regularly update the queue
|
|
||||||
thread(() {
|
|
||||||
queue_index = get_queue_index().assume_no_enum("if the server isn't reachable, it's ok to crash")
|
|
||||||
queue_list_inner = queue_list.gui_add(Column: [])
|
|
||||||
prev_artist = ""
|
|
||||||
prev_album = ""
|
|
||||||
for song_id get_queue() {
|
|
||||||
this_is_playing = if queue_index.eq(0) { queue_index = -1 true } else if queue_index.gt(0) { queue_index = queue_index.sub(1) false } else { false }
|
|
||||||
song = &database.get(song_id).assume1()
|
|
||||||
row = queue_list_inner.gui_add(Row: [])
|
|
||||||
text = if this_is_playing ">> " else ""
|
|
||||||
text = text.add(song.1)
|
|
||||||
if prev_artist.eq(song.2) {
|
|
||||||
if prev_album.eq(song.3) {
|
|
||||||
} else {
|
|
||||||
text = text.add("(on {0})".format(song.3))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
text = text.add("(by {0} on {1})".format(song.2 song.3))
|
|
||||||
}
|
|
||||||
row.gui_add(Text: text)
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
sleep(10)
|
|
||||||
queue_list_inner.gui_remove()
|
|
||||||
})
|
|
||||||
|
|
||||||
loop {
|
|
||||||
for event gui_updates() {
|
|
||||||
switch! event {
|
|
||||||
ButtonPressed([int ...]) {
|
|
||||||
e = event.noenum()
|
|
||||||
println("Pressed button {0}".format(e.to_string()))
|
|
||||||
match e {
|
|
||||||
&e.eq(&play_button) {
|
|
||||||
println("pressed play.")
|
|
||||||
play()
|
|
||||||
}
|
|
||||||
&e.eq(&stop_button) {
|
|
||||||
println("pressed stop.")
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// the button is in a row that is in the library,
|
|
||||||
// so pop()ing twice gets the library path.
|
|
||||||
// THIS WILL BREAK IF THE GUI LIBRARY SWITCHES TO IDs INSTEAD OF PATHS!
|
|
||||||
last = &e.pop().assume1()
|
|
||||||
slast = &e.pop().assume1()
|
|
||||||
matches = &e.eq(&library)
|
|
||||||
&e.push(slast)
|
|
||||||
&e.push(last)
|
|
||||||
if matches e else []
|
|
||||||
} {
|
|
||||||
// the second to last part of the path is the row within library, which is also the index in the db
|
|
||||||
song = &database.get(&e.get(e.len().sub(2)).assume1()).assume1()
|
|
||||||
println("Added song \"{0}\" to queue.".format(song.1))
|
|
||||||
queue_song(song.0)
|
|
||||||
}
|
|
||||||
true println("A different button was pressed (unreachable)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[]
|
|
||||||
}
|
|
@ -3,7 +3,17 @@ type myStruct [
|
|||||||
int,
|
int,
|
||||||
string
|
string
|
||||||
]
|
]
|
||||||
to give names to the fields, we define functions:
|
// to give names to the fields, we define functions:
|
||||||
fn count(s myStruct) s.0
|
fn count(s myStruct) s.0
|
||||||
// to allow users to change the value, add &myStruct to the valid types for s (only through references can values be changed)
|
// to allow users to change the value, add &myStruct to the valid types for s (only through references can values be changed)
|
||||||
fn note(s myStruct/&myStruct) s.1
|
fn note(s myStruct/&myStruct) s.1
|
||||||
|
|
||||||
|
my_struct := [12, "test"]
|
||||||
|
|
||||||
|
my_struct.count().debug()
|
||||||
|
|
||||||
|
my_struct.note().debug()
|
||||||
|
|
||||||
|
&my_struct.note() = "changed"
|
||||||
|
|
||||||
|
my_struct.note().debug()
|
||||||
|
2
mers/Cargo.lock
generated
2
mers/Cargo.lock
generated
@ -647,7 +647,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mers"
|
name = "mers"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colorize",
|
"colorize",
|
||||||
"edit",
|
"edit",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers"
|
name = "mers"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -636,11 +636,7 @@ impl BuiltinFunction {
|
|||||||
VSingleType::Tuple(vec![]),
|
VSingleType::Tuple(vec![]),
|
||||||
VSingleType::Tuple(vec![v
|
VSingleType::Tuple(vec![v
|
||||||
.get_any(info)
|
.get_any(info)
|
||||||
.expect("cannot use get on this type")
|
.expect("cannot use get on this type")]),
|
||||||
.dereference(info)
|
|
||||||
.expect(
|
|
||||||
"running get_any() on &[ ...] should give a reference...",
|
|
||||||
)]),
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -557,7 +557,7 @@ fn statement_adv(
|
|||||||
SStatementEnum::For(v, c, b) => {
|
SStatementEnum::For(v, c, b) => {
|
||||||
let mut linfo = linfo.clone();
|
let mut linfo = linfo.clone();
|
||||||
let container = statement(&c, ginfo, &mut linfo)?;
|
let container = statement(&c, ginfo, &mut linfo)?;
|
||||||
let inner = container.out(ginfo).inner_types(ginfo);
|
let inner = container.out(ginfo).inner_types_for_iters(ginfo);
|
||||||
if inner.types.is_empty() {
|
if inner.types.is_empty() {
|
||||||
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
|
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
|
||||||
}
|
}
|
||||||
@ -591,7 +591,6 @@ fn statement_adv(
|
|||||||
statement(case_action, ginfo, &mut linfo)?,
|
statement(case_action, ginfo, &mut linfo)?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if *force {
|
if *force {
|
||||||
let types_not_covered = og_type.fits_in(&covered_types, ginfo);
|
let types_not_covered = og_type.fits_in(&covered_types, ginfo);
|
||||||
if !types_not_covered.is_empty() {
|
if !types_not_covered.is_empty() {
|
||||||
|
@ -35,70 +35,6 @@ pub enum VSingleType {
|
|||||||
CustomTypeS(String),
|
CustomTypeS(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VSingleType {
|
|
||||||
/// None => Cannot get, Some(t) => getting can return t or nothing
|
|
||||||
pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> {
|
|
||||||
match self {
|
|
||||||
Self::Any
|
|
||||||
| Self::Bool
|
|
||||||
| Self::Int
|
|
||||||
| Self::Float
|
|
||||||
| Self::Function(..)
|
|
||||||
| Self::Thread(..)
|
|
||||||
| Self::EnumVariant(..)
|
|
||||||
| Self::EnumVariantS(..) => None,
|
|
||||||
Self::String => Some(VSingleType::String.into()),
|
|
||||||
Self::Tuple(t) => t.get(i).cloned(),
|
|
||||||
Self::List(t) => Some(t.clone()),
|
|
||||||
Self::Reference(r) => Some(r.get(i, gsinfo)?.reference()),
|
|
||||||
Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo),
|
|
||||||
&Self::CustomTypeS(_) => {
|
|
||||||
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// None => might not always return t, Some(t) => can only return t
|
|
||||||
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
|
||||||
match self {
|
|
||||||
Self::Any
|
|
||||||
| Self::Bool
|
|
||||||
| Self::Int
|
|
||||||
| Self::Float
|
|
||||||
| Self::String
|
|
||||||
| Self::List(_)
|
|
||||||
| Self::Function(..)
|
|
||||||
| Self::Thread(..)
|
|
||||||
| Self::EnumVariant(..)
|
|
||||||
| Self::EnumVariantS(..) => None,
|
|
||||||
Self::Tuple(t) => t.get(i).cloned(),
|
|
||||||
Self::Reference(r) => r.get_always_ref(i, info),
|
|
||||||
Self::CustomType(t) => info.custom_types[*t].get_always(i, info),
|
|
||||||
Self::CustomTypeS(_) => {
|
|
||||||
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get_always]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn get_always_ref(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
|
||||||
match self {
|
|
||||||
Self::Any
|
|
||||||
| Self::Bool
|
|
||||||
| Self::Int
|
|
||||||
| Self::Float
|
|
||||||
| Self::String
|
|
||||||
| Self::List(_)
|
|
||||||
| Self::Function(..)
|
|
||||||
| Self::Thread(..)
|
|
||||||
| Self::EnumVariant(..)
|
|
||||||
| Self::EnumVariantS(..) => None,
|
|
||||||
Self::Tuple(t) => Some(t.get(i)?.reference()),
|
|
||||||
Self::Reference(r) => r.get_always_ref(i, info),
|
|
||||||
Self::CustomType(t) => info.custom_types[*t].get_always_ref(i, info),
|
|
||||||
Self::CustomTypeS(_) => {
|
|
||||||
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get_always]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl VType {
|
impl VType {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self { types: vec![] }
|
Self { types: vec![] }
|
||||||
@ -117,13 +53,6 @@ impl VType {
|
|||||||
}
|
}
|
||||||
Some(out)
|
Some(out)
|
||||||
}
|
}
|
||||||
pub fn get_always_ref(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
|
||||||
let mut out = VType { types: vec![] };
|
|
||||||
for t in &self.types {
|
|
||||||
out.add_types(t.get_always_ref(i, info)?, info); // if we can't use *get* on one type, we can't use it at all.
|
|
||||||
}
|
|
||||||
Some(out)
|
|
||||||
}
|
|
||||||
/// returns Some(true) or Some(false) if all types are references or not references. If it is mixed or types is empty, returns None.
|
/// returns Some(true) or Some(false) if all types are references or not references. If it is mixed or types is empty, returns None.
|
||||||
pub fn is_reference(&self) -> Option<bool> {
|
pub fn is_reference(&self) -> Option<bool> {
|
||||||
let mut noref = false;
|
let mut noref = false;
|
||||||
@ -156,6 +85,27 @@ impl VType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VSingleType {
|
impl VSingleType {
|
||||||
|
/// None => Cannot get, Some(t) => getting can return t or nothing
|
||||||
|
pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> {
|
||||||
|
match self {
|
||||||
|
Self::Any
|
||||||
|
| Self::Bool
|
||||||
|
| Self::Int
|
||||||
|
| Self::Float
|
||||||
|
| Self::Function(..)
|
||||||
|
| Self::Thread(..)
|
||||||
|
| Self::EnumVariant(..)
|
||||||
|
| Self::EnumVariantS(..) => None,
|
||||||
|
Self::String => Some(VSingleType::String.into()),
|
||||||
|
Self::Tuple(t) => t.get(i).cloned(),
|
||||||
|
Self::List(t) => Some(t.clone()),
|
||||||
|
Self::Reference(r) => Some(r.get(i, gsinfo)?.reference()),
|
||||||
|
Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo),
|
||||||
|
&Self::CustomTypeS(_) => {
|
||||||
|
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> {
|
pub fn get_any(&self, info: &GlobalScriptInfo) -> Option<VType> {
|
||||||
match self {
|
match self {
|
||||||
Self::Any
|
Self::Any
|
||||||
@ -170,33 +120,40 @@ impl VSingleType {
|
|||||||
a
|
a
|
||||||
})),
|
})),
|
||||||
Self::List(t) => Some(t.clone()),
|
Self::List(t) => Some(t.clone()),
|
||||||
Self::Reference(r) => r.get_any_ref(info),
|
Self::Reference(r) => Some(VType {
|
||||||
|
// this is &a/&b/..., NOT &(a/b/...)!
|
||||||
|
types: r
|
||||||
|
.get_any(info)?
|
||||||
|
.types
|
||||||
|
.iter()
|
||||||
|
.map(|v| VSingleType::Reference(v.clone().to()))
|
||||||
|
.collect(),
|
||||||
|
}),
|
||||||
Self::EnumVariant(_, t) => t.get_any(info),
|
Self::EnumVariant(_, t) => t.get_any(info),
|
||||||
Self::EnumVariantS(..) => unreachable!(),
|
Self::EnumVariantS(..) => unreachable!(),
|
||||||
Self::CustomType(t) => info.custom_types[*t].get_any(info),
|
Self::CustomType(t) => info.custom_types[*t].get_any(info),
|
||||||
Self::CustomTypeS(_) => unreachable!(),
|
Self::CustomTypeS(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option<VType> {
|
/// None => might not always return t, Some(t) => can only return t
|
||||||
|
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
||||||
match self {
|
match self {
|
||||||
Self::Any
|
Self::Any
|
||||||
| Self::Bool
|
| Self::Bool
|
||||||
| Self::Int
|
| Self::Int
|
||||||
| Self::Float
|
| Self::Float
|
||||||
|
| Self::String
|
||||||
|
| Self::List(_)
|
||||||
| Self::Function(..)
|
| Self::Function(..)
|
||||||
| Self::Thread(..) => None,
|
| Self::Thread(..)
|
||||||
Self::String => Some(VSingleType::String.into()),
|
| Self::EnumVariant(..)
|
||||||
Self::Tuple(t) => Some(t.iter().fold(VType::empty(), |mut a, b| {
|
| Self::EnumVariantS(..) => None,
|
||||||
a.add_types(b.reference(), info);
|
Self::Tuple(t) => t.get(i).cloned(),
|
||||||
a
|
Self::Reference(r) => Some(VSingleType::Reference(r.get_any(info)?).to()),
|
||||||
})),
|
Self::CustomType(t) => info.custom_types[*t].get_always(i, info),
|
||||||
Self::List(t) => Some(t.reference()),
|
Self::CustomTypeS(_) => {
|
||||||
// TODO: idk if this is right...
|
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get_always]")
|
||||||
Self::Reference(r) => r.get_any_ref(info),
|
}
|
||||||
Self::EnumVariant(_, t) => t.get_any_ref(info),
|
|
||||||
Self::EnumVariantS(..) => unreachable!(),
|
|
||||||
Self::CustomType(t) => info.custom_types[*t].get_any(info),
|
|
||||||
Self::CustomTypeS(_) => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_reference(&self) -> bool {
|
pub fn is_reference(&self) -> bool {
|
||||||
@ -221,13 +178,6 @@ impl VType {
|
|||||||
}
|
}
|
||||||
Some(out)
|
Some(out)
|
||||||
}
|
}
|
||||||
pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option<VType> {
|
|
||||||
let mut out = VType { types: vec![] };
|
|
||||||
for t in &self.types {
|
|
||||||
out.add_types(t.get_any_ref(info)?, info); // if we can't use *get* on one type, we can't use it at all.
|
|
||||||
}
|
|
||||||
Some(out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VType {
|
impl VType {
|
||||||
@ -246,10 +196,10 @@ impl VType {
|
|||||||
}
|
}
|
||||||
no
|
no
|
||||||
}
|
}
|
||||||
pub fn inner_types(&self, info: &GlobalScriptInfo) -> VType {
|
pub fn inner_types_for_iters(&self, info: &GlobalScriptInfo) -> VType {
|
||||||
let mut out = VType { types: vec![] };
|
let mut out = VType { types: vec![] };
|
||||||
for t in &self.types {
|
for t in &self.types {
|
||||||
out.add_types(t.inner_types(info), info);
|
out.add_types(t.inner_types_for_iters(info), info);
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
@ -307,7 +257,7 @@ impl VSingleType {
|
|||||||
pub fn to(self) -> VType {
|
pub fn to(self) -> VType {
|
||||||
VType { types: vec![self] }
|
VType { types: vec![self] }
|
||||||
}
|
}
|
||||||
pub fn inner_types(&self, info: &GlobalScriptInfo) -> VType {
|
pub fn inner_types_for_iters(&self, info: &GlobalScriptInfo) -> VType {
|
||||||
match self {
|
match self {
|
||||||
Self::Tuple(v) => {
|
Self::Tuple(v) => {
|
||||||
let mut out = VType::empty();
|
let mut out = VType::empty();
|
||||||
@ -324,7 +274,7 @@ impl VSingleType {
|
|||||||
// function that takes no inputs
|
// function that takes no inputs
|
||||||
if let Some(out) = f.iter().find_map(|(args, out)| {
|
if let Some(out) = f.iter().find_map(|(args, out)| {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
Some(out.clone())
|
Some(out.clone().matches(info).1)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -334,21 +284,7 @@ impl VSingleType {
|
|||||||
VType::empty()
|
VType::empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Reference(r) => r.inner_types(info).reference(),
|
Self::Reference(r) => r.inner_types_for_iters(info).reference(),
|
||||||
_ => VType::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn inner_types_ref(&self, info: &GlobalScriptInfo) -> VType {
|
|
||||||
match self {
|
|
||||||
Self::Tuple(v) => {
|
|
||||||
let mut out = VType::empty();
|
|
||||||
for it in v {
|
|
||||||
out.add_types(it.reference(), info);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
|
||||||
Self::List(v) => v.reference(),
|
|
||||||
Self::Reference(r) => r.inner_types(info).reference(),
|
|
||||||
_ => VType::empty(),
|
_ => VType::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,6 @@ impl FormatGs for ScriptError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const PARSE_VERSION: u64 = 0;
|
|
||||||
|
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
pub err: ScriptError,
|
pub err: ScriptError,
|
||||||
pub ginfo: GSInfo,
|
pub ginfo: GSInfo,
|
||||||
@ -313,7 +311,6 @@ pub enum ParseErrors {
|
|||||||
FoundEofInType,
|
FoundEofInType,
|
||||||
FoundEofInsteadOfType,
|
FoundEofInsteadOfType,
|
||||||
RefTypeWithBracketsNotClosedProperly,
|
RefTypeWithBracketsNotClosedProperly,
|
||||||
InvalidType(String),
|
|
||||||
CannotUseFixedIndexingWithThisType(VType),
|
CannotUseFixedIndexingWithThisType(VType),
|
||||||
CannotWrapWithThisStatement(SStatementEnum),
|
CannotWrapWithThisStatement(SStatementEnum),
|
||||||
ErrorParsingFunctionArgs(Box<ParseError>),
|
ErrorParsingFunctionArgs(Box<ParseError>),
|
||||||
@ -354,7 +351,6 @@ impl FormatGs for ParseErrors {
|
|||||||
Self::RefTypeWithBracketsNotClosedProperly => {
|
Self::RefTypeWithBracketsNotClosedProperly => {
|
||||||
write!(f, "ref type with brackets &(...) wasn't closed properly.")
|
write!(f, "ref type with brackets &(...) wasn't closed properly.")
|
||||||
}
|
}
|
||||||
Self::InvalidType(name) => write!(f, "\"{name}\" is not a type."),
|
|
||||||
Self::CannotUseFixedIndexingWithThisType(t) => {
|
Self::CannotUseFixedIndexingWithThisType(t) => {
|
||||||
write!(f, "cannot use fixed-indexing with type ")?;
|
write!(f, "cannot use fixed-indexing with type ")?;
|
||||||
t.fmtgs(f, info, form, file)?;
|
t.fmtgs(f, info, form, file)?;
|
||||||
@ -1166,12 +1162,12 @@ pub mod implementation {
|
|||||||
}
|
}
|
||||||
Ok((VType { types }, closed_fn_args))
|
Ok((VType { types }, closed_fn_args))
|
||||||
}
|
}
|
||||||
fn parse_single_type(file: &mut File) -> Result<VSingleType, ParseError> {
|
// fn parse_single_type(file: &mut File) -> Result<VSingleType, ParseError> {
|
||||||
match parse_single_type_adv(file, false) {
|
// match parse_single_type_adv(file, false) {
|
||||||
Ok((v, _)) => Ok(v),
|
// Ok((v, _)) => Ok(v),
|
||||||
Err(e) => Err(e),
|
// Err(e) => Err(e),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
fn parse_single_type_adv(
|
fn parse_single_type_adv(
|
||||||
file: &mut File,
|
file: &mut File,
|
||||||
in_fn_args: bool,
|
in_fn_args: bool,
|
||||||
@ -1277,8 +1273,11 @@ pub mod implementation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
let out = parse_type(file)?;
|
let (out, close) = parse_type_adv(file, true)?;
|
||||||
fn_types.push((args, out));
|
fn_types.push((args, out));
|
||||||
|
if close {
|
||||||
|
break;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Some(')') => break,
|
Some(')') => break,
|
||||||
Some(other) => {
|
Some(other) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user