20 Commits 90ae7627e9 ... aee4426144

Author SHA1 Message Date
  mizusato aee4426144 adjust todos 2 years ago
  mizusato 064049f565 adjust 2 years ago
  mizusato eea49092c0 add todos 2 years ago
  mizusato 670c8d7cb4 adjust todo 2 years ago
  mizusato 1255b57d15 adjust todo 2 years ago
  mizusato df9f93a226 add error for unsupported cast 2 years ago
  mizusato 9cb94a5de3 fix 2 years ago
  mizusato 3432e1b32f update todos 2 years ago
  mizusato fd344f7bfe rx prevent sync feedback 2 years ago
  mizusato 72e827fcf1 rename ui::Input 2 years ago
  mizusato 64399976aa adjust todo 2 years ago
  mizusato 971041efba add todo 2 years ago
  mizusato 2209e4b0a8 adjust todos 2 years ago
  mizusato 6dbb854739 adjust todos 2 years ago
  mizusato e04aa529d9 add todos 2 years ago
  mizusato dc2176f110 add todos 2 years ago
  mizusato 0001dba11f adjust, new ref test 2 years ago
  mizusato 7ddd6546a5 fix 2 years ago
  mizusato 40a7a8209b adjust todo 2 years ago
  mizusato 7c2941c7fc dynamic cast 2 years ago

+ 2 - 0
.idea/dictionaries/mizusato.xml

@@ -26,6 +26,8 @@
       <w>exprs</w>
       <w>extern</w>
       <w>fscanln</w>
+      <w>icrc</w>
+      <w>icrp</w>
       <w>inspectable</w>
       <w>ireg</w>
       <w>kmmm</w>

+ 59 - 73
TODO

@@ -2,61 +2,89 @@ TODO
 
 ## Important
 
+parser change (_list) (s) (more_) convention prefixes/suffixes to (*), (+), etc.
+
+TYPE SYSTEM REFACTOR: (test/ref/ref.km)
+- no subtyping (thus no variance)
+- lift record type def to the same level as enum type def
+- no tuple; type Lambda[Input,Output] native; type Lambda2[Input1,Input2,Output]
+- type Pair[A,B] record { first: A, second: B }
+- update vd go-struct related code (including EnumDummyInterfaceMethod)
+- implicit contexts integrated in arguments (thus have default values)
+type - native;  // unit
+type Unknown native;
+type Error implements(Exception) native;
+type Bool union { const No, Yes };  // no as zero
+type Maybe[Some] union { const None, Some };
+type Result[Success,Failure] union { Success, Failure };
+type Source[T] restricted Observable[T]; // Observable no exception parameter
+'a'.[Maybe[String]]  // implicit conversion
+value.[Interface]  // implicit conversion
+computed.[]  // unbox
+type Number restricted Integer;
+new Number(1)  // only available in the module of Number
+new Record { ... }
+
+|-+ project
+  |-+ module1
+  | |-- @manifest.vd
+  | |-- foo.km
+  |
+  |-+ module2
+    |-- bar.km
+    |-- baz.km
+
+type #XXX -> type XXX data {record,union}
+
 overload: input expr "shape" signature matching
 
 field/case refs to list (xx.(&(branch) => ...))
 
+repl gui (text browser + line edit, tab completion)
+    - QTextBrowser < QTextEdit::append
+    - display details of large objects in another window
+    - consider full debugger (multiple tabs, console + timeline + source + gui)
+    - debugger (in machine), debugger server, debugger client
+    - reflect::Type, (param T -> Unknown)
+    - reflect::Value (implicit conversion)
+    - debug::Log('state', state)
+
 encode, decode, decode*: async version
 
-type #XXX -> type XXX data
+component function (can have preview)
 
 SQLite (QSqlDatabase) project source storage (exclusive conn, diff the whole db)
 
-module(can be private/public) < package
+module < project
 
 UUID for each type/const/operator
 
-package: kvdb (-> gist)
+project: kvdb (-> gist)
     content: modules(types,operators), entry point, dependencies, assets, docs
 
-ctor lambda -> generate default ctor (private) for protected/opaque type
-
-- ui::Input -> ui::TextInput
-- ui::TextView 2-way binding with Mutable[String] relay buffer (details on gist)
-- ListEdit: change mutating flag to relay buffer, similarly
-- Reactive: consider forbidding update(commit) during notification(notify)
-- ui::modal-get-text, ui::TextViewMultiLine, ui::InputMultiLine
-
-consider: type LiteralString protected String;
-
-dynamic cast (CaseRef[Interface,Concrete])
+ui::modal-get-text, ui::TextViewMultiLine, ui::TextInputMultiLine
 
 `interact-with-window` add option `min-size`; `popup` add option `rel-pos`
 
-revise argument count limit (consider accessing elements in TupleValue directly)
-
-implicit context default values
-
 context menu (QMenu.exec)
 
-consider hook-based event handling
-
 var wait = make(chan struct{})  // encapsulate to something in util
 
 qtbinding C side int vs. go side int (not the same type, fix it)
 
 api functions for file dialogs, font dialog, ...
 
-loader cache: (file-path, modified-time) => AST/asset
-
-"map" operation for homogenous tuple
-
-typeList and functionList: consider sorting by date
-
-consider making `container` module standalone
-
-refactor code of container types after generics available
+merge go118 branch after go1.18 released
 
+- {prefix,infix,suffix,continuation} operator
+    prefix (op foo)
+    infix (op infix foo)
+    suffix (op method Type.foo)
+    continuation (op control foo)
+    (op const)
+    (op variadic)
+    (op component)
+    (op message)
 
 ## IDE Roadmap / Design
 
@@ -74,39 +102,10 @@ file {
 
 module can be configured as 'no module prefix' (mod:: not displayed in IDE)
 
-- {prefix,infix,suffix,continuation} operator
-    prefix (function)
-    infix (operator)
-    suffix (method)
-    continuation (control)
-
-export 'b9adcfb3-7830-4092-9fd2-fc414172c774'
-function tick {interval: Number}: Source[unit] {
-    // code
-}
-export 'c4dfe913-35f5-46ee-bd46-232d778cffd4'
-method List.length: Number {
-    // code
-}
-export '89faeba7-e533-4f72-92db-93aab92c3a40'
-operator + (l: Integer, r: Integer): Integer {
-    // code
-}
-export '6e95ceb3-a479-4586-a788-ee9a2284ca1e'
-control await[A,B] (a: Async[A], k: &(A) => Async[B]): Async[B] {
-    // code
-}
-
 - Browser-like navigation (statement <=> page) (back, forward, recent history)
 
 - Tags for functions/types (tags instead of classes/folders)
 
-- { Type.method obj-subtype }
-
-- call function with explicit context passing { f(ctx{=:eq}) x }
-
-- no function ref, function -> operator
-
 - language-based debug-log (we can know the type)
 
 - sample input (to get a clear preview of the dataflow)
@@ -120,20 +119,7 @@ control await[A,B] (a: Async[A], k: &(A) => Async[B]): Async[B] {
 
 - API: consider renaming wait and tick
 
-
-## Reflection
-
-type type[T] protected Type;
-type Type native;
-type value[T] protected Value;
-type Value native;
-|reflect::type[Foo]|
-|reflect::value| "abc"
-// type assertion etc. implemented by (native) functions
-
-
-## API Refactor
-
-- API: revise resource management for files, ... (consider Disposable[T] monad)
+- API: revise resource management for files
+    consider Disposable[T] (ctx-based disposal or persist closable object)
 
 

+ 3 - 1
interpreter/compiler/checker/checked/expr.go

@@ -112,6 +112,7 @@ func (InteriorRef) implExpr() {}
 type InteriorRef struct {
 	Base     *Expr
 	Index    uint
+	Table    *DispatchTable  // optional, used in dynamic cast
 	Kind     InteriorRefKind
 	Operand  InteriorRefOperand
 }
@@ -119,11 +120,12 @@ type InteriorRefKind int
 const (
 	RK_Proj InteriorRefKind = iota
 	RK_Case
+	RK_InterfaceCase
 )
 type InteriorRefOperand int
 const (
 	RO_Record InteriorRefOperand = iota
-	RO_Enum
+	RO_EnumOrInterface
 	RO_ProjRef
 	RO_CaseRef
 )

+ 38 - 5
interpreter/compiler/checker/ctx_type.go

@@ -181,6 +181,12 @@ func (cc *checkContext) getExpectedLambda(t typsys.Type, loc source.Location) (t
 	}
 }
 
+func (cc *checkContext) unboxInterface(expr *checked.Expr) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
+	return cc.unboxInterfaceFromType(expr.Type)
+}
+func (cc *checkContext) unboxInterfaceFromType(t typsys.Type) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
+	return unboxInterface(t, cc.exprContext.ModName)
+}
 func (cc *checkContext) unboxEnum(expr *checked.Expr) (*typsys.Enum, *typsys.TypeDef, ([] typsys.Type), bool) {
 	return cc.unboxEnumFromType(expr.Type)
 }
@@ -219,11 +225,11 @@ func (cc *checkContext) unboxInteriorReferableEnum(expr *checked.Expr) (*typsys.
 	var enum, enum_def, enum_args, ok = cc.unboxEnum(expr)
 	if ok {
 		var base_t = &typsys.NestedType { Content:
-		typsys.Ref {
-			Def:  enum_def,
-			Args: enum_args,
-		} }
-		return enum, enum_args, checked.RO_Enum, base_t, true
+			typsys.Ref {
+				Def:  enum_def,
+				Args: enum_args,
+			} }
+		return enum, enum_args, checked.RO_EnumOrInterface, base_t, true
 	} else {
 		{ var base_t, field_t, ok = coreProjRef_(expr.Type)
 		if ok {
@@ -242,5 +248,32 @@ func (cc *checkContext) unboxInteriorReferableEnum(expr *checked.Expr) (*typsys.
 		return nil, nil, -1, nil, false
 	}
 }
+func (cc *checkContext) unboxInteriorReferableInterfaceDef(expr *checked.Expr) (*typsys.TypeDef, ([] typsys.Type), checked.InteriorRefOperand, typsys.Type, bool) {
+	var _, def, t_args, ok = cc.unboxInterface(expr)
+	if ok {
+		var base_t = &typsys.NestedType { Content:
+			typsys.Ref {
+				Def:  def,
+				Args: t_args,
+			} }
+		return def, t_args, checked.RO_EnumOrInterface, base_t, true
+	} else {
+		{ var base_t, field_t, ok = coreProjRef_(expr.Type)
+			if ok {
+				var _, def, t_args, ok = cc.unboxInterfaceFromType(field_t)
+				if ok {
+					return def, t_args, checked.RO_ProjRef, base_t, true
+				}
+			} }
+		{ var base_t, case_t, ok = coreCaseRef_(expr.Type)
+			if ok {
+				var _, def, t_args, ok = cc.unboxInterfaceFromType(case_t)
+				if ok {
+					return def, t_args, checked.RO_CaseRef, base_t, true
+				}
+			}}
+		return nil, nil, -1, nil, false
+	}
+}
 
 

+ 17 - 0
interpreter/compiler/checker/errors.go

@@ -762,6 +762,23 @@ func (e E_NotImplementation) DescribeError() richtext.Block {
 	)
 }
 
+type E_DynamicCastFromNonInterface struct {
+	Type  string
+}
+func (e E_DynamicCastFromNonInterface) DescribeError() richtext.Block {
+	return makeErrorDescBlock (
+		"cannot dynamically cast from non-interface type",
+		e.Type,
+	)
+}
+
+type E_DynamicCastToInterface struct {}
+func (E_DynamicCastToInterface) DescribeError() richtext.Block {
+	return makeErrorDescBlock (
+		"cannot dynamically cast to interface type: unsupported feature",
+	)
+}
+
 type E_BlankTerm struct {}
 func (E_BlankTerm) DescribeError() richtext.Block {
 	return makeErrorDescBlock (

+ 1 - 1
interpreter/compiler/checker/expr.go

@@ -63,7 +63,7 @@ func checkPipe(in *checked.Expr, pipe ast.VariousPipe) ExprChecker {
 	case ast.PipeGet:
 		return checkGet(in, P.Key, loc)
 	case ast.PipeInterior:
-		return checkInterior(in, P.Key, loc)
+		return checkInterior(in, P.Module, P.Item, loc)
 	default:
 		panic("impossible branch")
 	}

+ 65 - 7
interpreter/compiler/checker/expr_misc.go

@@ -2,6 +2,7 @@ package checker
 
 import (
 	"kumachan/interpreter/lang/ast"
+	"kumachan/interpreter/lang/common/name"
 	"kumachan/interpreter/lang/common/source"
 	"kumachan/interpreter/compiler/checker/typsys"
 	"kumachan/interpreter/compiler/checker/checked"
@@ -25,12 +26,69 @@ func checkCast(arg_node ast.Expr, target ast.VariousType, loc source.Location) E
 	})
 }
 
-func checkInterior(arg *checked.Expr, key ast.Identifier, loc source.Location) ExprChecker {
+func checkInterior(arg *checked.Expr, mod_name ast.ModuleName, item_name ast.Identifier, loc source.Location) ExprChecker {
 	return makeExprChecker(loc, func(cc *checkContext) checkResult {
-		var key_str = ast.Id2String(key)
+		var mod_name_not_empty = mod_name.NotEmpty
+		{ var i_def, i_args, op, base, is_interface = cc.unboxInteriorReferableInterfaceDef(arg)
+		if !(is_interface) && mod_name_not_empty {
+			return cc.propagate(source.MakeError(arg.Info.Location,
+				E_DynamicCastFromNonInterface {
+					Type: cc.describeType(arg.Type),
+				}))
+		}
+		if is_interface {
+			var c_name, err = NameFrom(
+				mod_name, item_name, cc.exprContext.ModuleInfo,
+			)
+			if err != nil {
+				return cc.propagate(err)
+			}
+			var ctx = cc.typeConsContext()
+			var c_def_, c_def_desc, exists = ctx.ResolveTypeDefName(c_name)
+			if !(exists) {
+				return cc.propagate(source.MakeError(item_name.Location,
+					E_TypeNotFound { Which: c_def_desc() }))
+			}
+			var c_def = c_def_.TypeDef
+			var _, c_is_interface = c_def.Content.(*typsys.Interface)
+			if c_is_interface {
+				return cc.error(E_DynamicCastToInterface {})
+			}
+			var p = ImplPair {
+				ConcreteType:  c_def,
+				InterfaceType: i_def,
+			}
+			var table, ok = cc.exprContext.DispatchMapping[p]
+			if !(ok) {
+				var c_type_name = name.TypeName { Name: c_name }
+				var i_type_name = i_def.Name
+				return cc.error(
+					E_NotImplementation {
+						Type:      c_type_name.String(),
+						Interface: i_type_name.String(),
+					})
+			}
+			var c_type = &typsys.NestedType { Content: typsys.Ref {
+				Def:  c_def,
+				Args: i_args,
+			} }
+			var ref_type = cc.getType(coreCaseRef(
+				base,
+				c_type,
+			))
+			return cc.assign(
+				ref_type,
+				checked.InteriorRef {
+					Base:    arg,
+					Table:   table,
+					Kind:    checked.RK_InterfaceCase,
+					Operand: op,
+				})
+		} }
+		{ var key = ast.Id2String(item_name)
 		{ var record, op, base, is_record = cc.unboxInteriorReferableRecord(arg)
 		if is_record {
-			var index, exists = record.FieldIndexMap[key_str]
+			var index, exists = record.FieldIndexMap[key]
 			if !(exists) { goto key_not_found }
 			var field_t = record.Fields[index].Type
 			var ref_t = cc.getType(coreProjRef(base, field_t))
@@ -49,7 +107,7 @@ func checkInterior(arg *checked.Expr, key ast.Identifier, loc source.Location) E
 			var cd *typsys.TypeDef
 			var found = false
 			for i, case_def := range enum.CaseTypes {
-				if case_def.Name.ItemName == key_str {
+				if case_def.Name.ItemName == key {
 					ci = uint(i)
 					cd = case_def
 					found = true
@@ -72,11 +130,11 @@ func checkInterior(arg *checked.Expr, key ast.Identifier, loc source.Location) E
 				})
 		} }
 		key_not_found:
-		return cc.propagate(source.MakeError(key.Location,
+		return cc.propagate(source.MakeError(item_name.Location,
 			E_NoSuchFieldOrCase {
-				FieldName: key_str,
+				FieldName: key,
 				TypeName:  cc.describeTypeOf(arg),
-			}))
+			})) }
 	})
 }
 

+ 23 - 0
interpreter/compiler/checker/interface.go

@@ -200,4 +200,27 @@ func methodType(con *typsys.TypeDef, impl *typsys.TypeDef, raw typsys.Type) typs
 	})
 }
 
+func getInterface(t typsys.Type) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
+	var nested, is_nested = t.(*typsys.NestedType)
+	if !(is_nested) { return nil, nil, nil, false }
+	var ref, is_ref = nested.Content.(typsys.Ref)
+	if !(is_ref) { return nil, nil, nil, false }
+	var interface_, is_interface = ref.Def.Content.(*typsys.Interface)
+	if !(is_interface) { return nil, nil, nil, false }
+	return interface_, ref.Def, ref.Args, true
+}
+func unboxInterface(t typsys.Type, mod string) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
+	var interface_, def, args, is_interface = getInterface(t)
+	if is_interface {
+		return interface_, def, args, true
+	} else {
+		var inner, _, exists = typsys.Unbox(t, mod)
+		if exists {
+			return unboxInterface(inner, mod)
+		} else {
+			return nil, nil, nil, false
+		}
+	}
+}
+
 

+ 1 - 0
interpreter/compiler/checker/type_construct.go

@@ -33,6 +33,7 @@ func (ctx TypeConsContext) ResolveTypeDefName(n name.Name) (TypeDef, func()(stri
 		return n.String()
 	}
 	var def, exists = ctx.TypeReg[name.TypeName { Name: n }]
+	// TODO: legacy code: consider removing the 2nd return value (desc)
 	return def, desc, exists
 }
 

+ 0 - 0
interpreter/compiler/checker/type_register.go


Some files were not shown because too many files changed in this diff