<< >> #
bit-ops & | ~ &~
op=
-- split values so I can have an array of just the value (1 byte for u8)
- integers, unsigned, bitfield, float, double?
- pointers
- owned or borrowed
- allow "do stuff" as a stand-alone statement (scope)
- 'use' labels *must* appear in case statements.
-- re-read parsergen lit-doc and make sure it is still coherent.
Next version (Govetts Creek):
- functions and procedures
others.
It even has Box<> to create on heap instead of stack.
-Why doesn't I just do that? Partly because I don't have classes yet!!
+Why don't I just do that? Partly because I don't have classes yet!!
I like a simple syntax to test if a pointer is over-loaded.
if pointer?
fun foo<x:thing>(a:x, b:x) : x
+------------------------
+Years later - March 2021
+
+I need somewhere to start so I need to be able to ignore lots of this detail.
+So in the first instance all references are counted references. They must refer
+to a struct that contains 'refcount'.
+
+A reference is declared with
+ name : ref base-type
+and the base object can be accessed with
+ name.ref
+though this can sometimes be inferred from "name".
+In particular
+ name.foo
+will find 'foo' either as an attribute of name, or of what name refers to.
+If name refers to a reference, this recurses.
+
+A ref can be checked with "name.valid"
+
+A new object can be allocated with "name.new()", which returns the ref.
+So "name.new().valid" is true if the allocation succeeded, which is always
+will on Linux.
+
+Future ideas might include:
+ type name : ref(attr,list) basetype
+where attr,list can include borrow,counted,single, etc
+
-I want to add functions and procedures soon. I should decide on syntax at least.
+I want to add functions and procedures soon. I should decide on syntax
+at least.
-The args to a function are effective a struct, so I want it to look the same.
-C doesn't allow "int a, b, c" in the parameters, which I think is clumsy.
-struct can be
+The args to a function are effectively a struct, so I want it to look
+the same. C doesn't allow "int a, b, c" in the parameters, which I
+think is clumsy. struct can be
struct name:
a,b,c:number
func name:
arg1, arg2: type
arg3: type2
- returns type
+ return type
do:
stuff
variable that it might be nice to follow the Pascal approach of
assigning to the function name?? or having
- func name:
+ func name
args:types
- returns:
+ return
results:types
- do:
+ do
statements
A shorter version would be
func name(args:types;args:types):type { }
or
- proc name(args:types;args:types):(result:type;...) {}
+ func name(args:types;args:types):(result:type;...) {}
+
+Can arguments be optional?
+ - yes, if "= value" follows the type
+Can we have variable number of args
+ - yes. Any arg can be an inline-array. The last arg can
+ have undefined length [].
+Can named args be passed in
+ - yes, once I have a syntax for manifest structs
+
+Arrays seem very different from structs.
+ - they don't have names (as types)
+ - they don't need grouping in function params??
+Does this make any sense?
+Maybe I should require the grouping
+ printf("%d %d %d", (1,2,3))
+??
+
+
+Functions can be used before being declared - analysis happens after all is read.
+
+'main' is given an array of strings of unknown length.
+So I need the formal parameter to accept variable-length arrays.
+Do I use
+ argv:[] string
+and support "argv.len", or do I use
+ argv:[argc] string
+which instantiates argc with the length?
+Probably the latter.
+
+Arrays have to be passed by reference, they are const if :: used for type.
+Structs .. ditto.
+Strings and numbers are immutable.
+
+So I need functions to turn strings into number or bool.
+Just bool() and number() for now.
+So
+DONE 1/ change 'program' to make everything a string, and use functions to get numbers.
+DONE 2/ change 'program' to receive an array with bindably size
+DONE 3/ change 'program' to 'func main' etc
+DONE4/ allow more functions.
+
+What syntax to use for formal types?
+I will need type parameterisation some day. For now I just need the
+size of an array to be parameterised.
+ argv:[argc]string
+looks like normal type. But it isn't clear if argc is a global constant
+or a variable.
+ argv:[argc:int]string
+seem redunant because of course the array index is an int.
+ argv:[argc:]string
+might be acceptable.
+It is like leaving out the type is
+ a := 4
+
+So let's go with that.
+
+
+DONE To handle functions, and recursion in particular, I need a concept of a
+stack frame in the interpreter. This needs to include room for
+parameters and results and local variables. So a function needs to know
+the size of its frame, and each variable needs an offset.
+So I need to switch 'program' over to this approach before adding
+functions.
+Then the function frame will have a results frame separate from the
+main frame, as it can last longer. So each variable needs to be marked
+as 'result' or not.
Binary: and then, or else, integer division
Prefix: int
- Suffix: dereference
+ Suffix: dereference (ref)
Do I want COND ? IFTRUE : IFFALSE
a @@= b
does a deep copy
-What types do operators act one?
+What types do operators act on?
numbers + - * / %
bitsets & | ~ &~
An operator that modifies a variable is something I wanted to avoid.
var ? oldval = newval
could 'use false' if it fails.
+
+# decided so far:
+
+ + addition or abs value
+ - subtraction or negation
+ * multiply
+ / div
+ % remainder
+ ++ catentate
+ () group
+ if else conditional
+ and, or, not Boolean
+ and then Boolean
+ or else Boolean
+ = assignment
+ : type
+ < > != == <= >= comparison
+ [ ] array access
+ . field access
+ " ' ` quoting
+ , ; list
+ { } grouping
+
+# expect
+ & bit and
+ | bit or
+ &^ bit subtract
+ ^ bit invert (prefix or infix)
+ # 1<< (prefix)
+ << >> shift
+
+ += -= *= /= %= ++= &= |= &^= ^=
+ What about boolean? and=?
+ if c: a=True // if not c: a=False
+
+# undecided
+ ? ! @ $ \ ~
+ -- ** @@ ^^
+
+ Equiv of "a ?: b". i.e. a if a else b. Only works if non-Bools can be tested.
--- /dev/null
+References can be 'owned' or 'borrowed'.
+They can also be 'shared' or 'exclusive'
+And maybe I need 'const' as well??
+
+Borrowed references need to be borrowed from somewhere, and it must be
+clear where.
+- from a caller via function parameter passing
+- from a data structure via a lookup function - if structure is
+ append-only
+- from a lock - which asserts ownership while held
+
+Owned references can be:
+ refcounted - are these borrowed from the refcount?
+ single - there is only ever one owner
+The difference is that 'single' uses zero bits for the refcount.
+So maybe if a structure has a field declared 'refcount' it is
+refcounted, else it can only be 'single'.
+
+A pointer is declared as
+ name: @type
+Attributes can appear afterwards
+ name: @type owned shared
+
+ownership is transferred using
+ new := *old (??)
+This nulls the variable or marks it invalid.
+An assignment like
+ new : @type = old
+will create a new owned reference and is only permitted for refcounted
+
+Owned references are dropped when they are replaced or go out of scope.
+This results in a dec of refcount and possible a free - or "close" once
+I have objects.
+
+When a reference is borrowed I need to know where it is borrowed from.
+The owner can be some other (complex) object or the call stack.
+It might be some set of objects if we don't know for certain.
+
+
+What are some difficult pointer usages that need clear understanding.
+
+1/ linked lists and trees are easy. The link is owned.
+2/ double-linked lists have two problems.
+ A/ The 'prev' link cannot be owned - so who is it borrowed from?
+ B/ The tail link back to the header.
+
+The links aren't where the ownership resides. The ownership resides in
+the total data structure - the list.
+The list - represented by the head - owns the references to all members.
+The pointers are just record keeping.
+
+Pointers *can* store ownership, but they are just one option.
+A function can declare that some ownership is stored or released
+without the language being able to confirm it.
+
+I need to write some code to explore what I want.
+
+A ref is dereferenced with '@', but it can be left off if there is a field
+reference, so "ref@.foo" and "ref.foo" are the same.
+
+ref@new allocates a new object
+ref@valid is true if the ref points to something
+ref@drop drops the ref and invalidates the pointer ??
+
+Maybe
+ foo:@type = @new()
+ foo = @null
+
+ foo?
+
+
+
+----
+I wonder if I want user-defined reference attributes.
+This would require generic support in the language.
+The idea is that the language gurantees some simple properties
+and the code provie the manipulations.
+
+So the "owned" attribute is declared as 'single' meaning it isn't
+copied with the pointer. However it can be explicitly copied
+by a "get_ref" function which returns an 'owned' flag without consuming one.
+
+Some attributes would be "sticky" meaning they follow a value around.
+"mut" or "ro" would be like this.
+Some fields in an object may only be accessed or changed by a method,
+which may explicitly change flags.
+"ro" might prevent updates, "mut" might permit them, "hidden" might
+prevent all accesses, or "xray" might be needed to see anything.
+
+Attributes could define trigger functions which are called in
+certain circumstances.
+"owned" might call free() when the value goes out of scope without being consumed.
+
+Tracking the connection between "owned" and "borrowed" might be
+tricky. I need some code to play with.