I started working on auto-completion in my Netbeans plugin. I'm starting with import completion.
Typically with NB this is done by indexing packages(pods) & types in source folders and/or libs folder.
I could do that with Fan (at least for the sources anyway), for libraries not sure yet what is the proper way to do it(reflection probably - will look how they do it for java) ... but I think I remember that Fan has it's own "Type database" ... would it make sense for me to use that instead of probably slower parsing/indexing ? Also does that "DB" contain all of the pods/types in the repo or just the ones that where "loaded".
If you think it makes sense to use the DB, any info on using it ?
Thanks.
brianWed 19 Aug 2009
I think the simplest solution is to break things up into:
current pod being compiled
external pods
I am not sure how Java IDEs work, but I assume they "index" the entire project from source. I would expect that in a Fan IDE, only the current pod would be indexed by source, and external pods would use the pre-compiled pod files via reflection. In this model the IDE works like the compiler does - the compiler does type checking against pods, not source. So if you want to auto-completion for a new method in an external pod, then that pod needs to be compiled first. The seems to simplify the problem and should make for more efficient IDEs - they only need to index the current pod being worked on (by index I mean build an AST model).
To use reflection in the IDE, the simplest thing is to just use "sys.jar" and its Java implementation of the sys APIs. For example to call Pod.find, you can use the Java class fan.sys.Pod. Using Fan APIs from Java is really straight forward. Just ensure that you set the "fan.home" system property before you load any classes from "sys.jar". Then everything is booted up in the static initializer for fan.sys.Sys.
What won't work today is reloading a pod which has been recompiled. But you might be able to handle this yourself in brute force fashion by flushing the classloader used to load sys, and then booting Fan up again.
You might also what to check out what Cheeser did for tradewinds since he is hosting a Fan runtime from Java.
tcolarWed 19 Aug 2009
Right, compiled POds through type DB should be faster/more convenient than parsing. I would only parse sources for currently opened pods in the IDE most likely.
I'll investigate some more the reflection and see how it goes, if I can get it to work without needing a runtime that would be nice.
Just ensure that you set the "fan.home" system property before you load any classes > from "sys.jar". Then everything is booted up in the static initializer for fan.sys.Sys.
All see how that goes, I seem to remember that you could not change/define on the fly Java system properties, so I might have to spawn another VM / Fan runtime anyway.
What won't work today is reloading a pod which has been recompiled. But you might be > able to handle this yourself in brute force fashion by flushing the classloader used > to load sys, and then booting Fan up again.
The type database wiki page (which I can't seem to find anymore) said something along the line of "It will update change pods/types automatically at runtime", but i guess from what you just said that it does so only at BOOT time, right ?
Thanks.
brianWed 19 Aug 2009
I seem to remember that you could not change/define on the fly Java system properties
Yeap you can. Just need to do it before you load the Sys class.
The type database wiki page (which I can't seem to find anymore) said something along the line
Technically the typedb is one piece of the overall reflection subsystem. What you need and will be using isn't the typedb per se, but rather just the reflection APIs to Pod/Type/Slot definitions.
Although if you want, you might just drop down a level and instead of using the reflection APIs, use the code in fanx.fcode to parse the type/slot meta-data straight out the pod file and manage it yourself. This is basically what Pod/Type/Slot are doing - just building an in-memory model of the fcode and then eventually mapping it to Java classes. But note, just using reflection doesn't actually emit Java classes - this is one of the cool things about Fan, you can do reflection before the Java classes are actually emitted.
tcolarWed 19 Aug 2009
Sounds good, that should get me what I need.
I might go the fanx.fcode route, because it might make it easier to "reload" pod that changed (timestamp)
tcolarWed 19 Aug 2009
Sorry, I forgot to ask this: Does the reflection API have access to the doc(fandoc), if not I might go back to using the sources, because it's definitely nice to have the fandoc to go along with the completion proposals.
Update: I guess FDoc in fanx is the answer.
brianWed 19 Aug 2009
Sorry, I forgot to ask this: Does the reflection API have access to the doc(fandoc),
Yes, in Fan this is super simple:
fansh> Str#get.doc
Get the character at the zero based index as a Unicode code point.
Negative indexes may be used to access from the end of the string.
This method is accessed via the [] operator.
In the pod it is stored in a very simple text file. See fanx.fcode.FDoc and the impls for Pod.doc and Type.doc
tcolarFri 4 Sep 2009
It would be nice if Pod.fan had a reload() method that would do the same as load() but not prevent loading if already in the cache(lazy cache).
I can't seem to extend/ use Pod to make it reload updated/new pods because of this and the fact much of it is not public.
I guess I have to use FPod for now.
Also i find this a bit weird:
fpod = new FPod(null, null, null);
fpod.readFully(new ZipInputStream(SysInStream.java(in)));
shouldn't readFully() rather be a static method that returns an FPod.
brianFri 4 Sep 2009
The problem is that it would introduce an extremely confusing issue of what to do with existing instances and classes using the old Pod definition.
Reloading scripts is one thing (and we already do it), because each version of the pod gets its own unique pod name.
But well-defined pod modules don't work that way.
tcolarFri 4 Sep 2009
OK. I should be alright with FPod for my purpose.
tcolarThu 10 Sep 2009
I started working on completion. I have imports completion working now, and it shows the relevant "fandoc" for the selected pod/type in the completion windows which is nice.
The thing though is that Pod.doc & Type.doc returns the doc as plain text. For some detailed(syntax heavy) doc such as sys:Buff or sys::Depend, that looks quite ugly.
So anyway my question is:
Is there a method somewhere to parse the doc into HTML? I know Sidewalk does this, but is that code in the Fan distro.
I don't mind the Fandoc Syntax being the same as used in the fandev Wiki, but if the code to parse fandocs is not available in the fan distro, this is not useful / usable.
One thing is that i need to run this from java, since it's a pure Fan library I can't call it directly like I do with fan classes implemented in Java(such as fanx.fcode.FPod).
I have access to the fan user fan distro, so I guess I can "use" it
One way would be for me to do something like call a little fan script that return the doc like: java fanx.tools.Fan fanIde.getDoc sys type (with getDoc using FandocParser as in your example), it would work, but this seem quite inefficient (spawning vm's) and limited.
I'm thinking maybe I could spawn One Fan shell process and interact with that, but I'm not sure if it's "capable" enough to return me what I need?
Any suggestion on a preferred way to do something like this (a.k.a using a Fan lib from Java) ?
andyFri 11 Sep 2009
This is just a classloader issue, which I'm not sure we ever really cemented a design for. Brian can correct me, but I believe if you just use FanClassLoader to load the fandoc class into the same VM - then just use it directly - it will work. Thats not the long-term solution here though.
brianFri 11 Sep 2009
@tcolar,
Since you already linking against sys.jar, I would suggest just using reflection to convert from fandoc to HTML. It is pretty "simple" using this code:
String fandoc = "you want to do *what*!";
FanObj parser = (FanObj)Type.find("fandoc::FandocParser").make();
FanObj doc = (FanObj)parser.type().method("parseStr").call(parser, fandoc);
String html = (String)doc.type().method("write").call(doc, Type.find("fandoc::HtmlDocWriter").make());
System.out.println(html);
Don't you wish Java had a -> operator!
tcolarSat 12 Sep 2009
Ha cool, the FanObj casting was the trick i was missing. Thanks. Same code in Fan would be so much shorter/cleaner !
tcolarWed 23 Sep 2009
I'm trying to use this but I keep getting an error:
sys::Err: java.lang.NoClassDefFoundError: Could not initialize class fan.fandoc.LineType
at fan.sys.Err.make(Err.java:43)
at fan.sys.Method.invoke(Method.java:550)
at fan.sys.Method$MethodFunc.call(Method.java:267)
at fan.sys.Method.call(Method.java:151)
at net.colar.netbeans.fan.indexer.FanPodIndexer.fanDocToHtml(FanPodIndexer.java:168)
at net.colar.netbeans.fan.indexer.FanPodIndexer.getPodTypeDoc(FanPodIndexer.java:148)
at net.colar.netbeans.fan.completion.FanCompletionHandler.document(FanCompletionHandler.java:95)
sys.jar is loaded, so I'm not surer what's going on ?
Any clue ?
brianWed 23 Sep 2009
Any clue ?
Not really.
I tried that our snippet of Java code inside sys.jar and it worked.
might want to be some debug into FanClassLoader - something must be failing there
tcolarWed 23 Sep 2009
I think I found what the deal was, i have two versions of fan, since at some point i was trying to build fan itself, I think this is where there is a mixup, though i'm not sure exactly how yet.
tcolarFri 25 Sep 2009
Nevermind it still fails, I notice there is one error very first before the LineType one.
Preamble:sys::
sys::Err: java.lang.NoSuchMethodError: fan.sys.FanObj.toImmutable(Ljava/lang/Object;)Ljava/lang/Object;
at fan.sys.Err.make(Err.java:43)
at fan.sys.Method.invoke(Method.java:550)
at fan.sys.Method$MethodFunc.call(Method.java:267)
at fan.sys.Method.call(Method.java:151)
at net.colar.netbeans.fan.indexer.FanPodIndexer.fanDocToHtml(FanPodIndexer.java:168)
....
Does it make any more sense ?
KevinKelleyFri 25 Sep 2009
toImmutable was one of the very recent changes, so it looks a lot like you've got some out of sync code somewhere. Using a sys.jar that's out of date?
tcolarFri 25 Sep 2009
Ok, I'll check that out. I don't think I do use another one, but maybe I put sys.jar in my classpath at some point for debugging or something.
tcolarFri 25 Sep 2009
OK< i figures out the issue with sys.jar ... now i have a new weirdness.
Using same code here provided by Brian:
String fandoc = "you want to do *what*!";
FanObj parser = (FanObj)Type.find("fandoc::FandocParser").make();
FanObj doc = (FanObj)parser.type().method("parseStr").call(parser, fandoc);
String html = (String)doc.type().method("write").call(doc, Type.find("fandoc::HtmlDocWriter").make());
System.out.println(html);
I do get the html printed out to stdout(presumably by the write method ?), but the html var is null ...
Maybe I'm just tired.
andySat 26 Sep 2009
HtmlDocWriter.make takes an OutStream as an arg with a default value of Sys.out, so pass in a Buf to capture the output in memory.
tcolarMon 28 Sep 2009
Sorry for being thick, but i can't quite find something that work
FanObj writer = (FanObj)Type.find("fandoc::HtmlDocWriter")
.method("make").call(buf.out());
doc.type().method("write").call(doc, writer);
html = buf.flip().readAllStr();
tcolarMon 28 Sep 2009
Doh! Thanks, should have read the fandoc more carefully. As an aside, it would be nice if IllegalArgumentException exception was more detailed: Ex: Expected Outpustream but got Buf instead :)
brianMon 28 Sep 2009
As an aside, it would be nice if IllegalArgumentException exception was more detailed: Ex: Expected Outpustream but got Buf instead
Fan doesn't generate that exception - it is raised by Java reflection and we just wrap it as ArgErr
tcolarMon 28 Sep 2009
Ha, true, too bad.
tcolarFri 20 Nov 2009
Ok, I'm working on this once again. I've decided to use the FPod facilities as the base for the completion, this proves to be very easy and practical!
Netbeans usually works fully from sources ... but working from sources is pretty difficult especially with a language like Fan with implicit casting, and inferred types etc. Also the indexing Netbeans uses, based on Lucene, appears buggy and doesn't seem to me like a very good solution for the completion job either.
Anyway, now the trick to this, is the code that's being "currently" worked on: It's not compiled yet, and potentially not compilable yet (incomplete code) ... so I still have to analyze the source for those, what I was wondering is whether there are built-in facilities in Fan that could help me .. say for example something to help me figure out and inferred variable Type and things like that.
I know Andy mentioned also working on some AST builder from fan source and was wondering if some of that might help me or if you have other suggestion on good ways to implement this (Since fan always seem to have some very nice built-in feature i miss at first)
If not, I'm going to start from my ANTLR built AST but will have to figure out lots of other things to get it to work right (like trying to figure out an inferred type).
Thanks.
brianSat 21 Nov 2009
Well the simplest way would be use the fcode from the last successful compile. That obviously wouldn't pick up changes during the current cycle, but I expect would be a pretty good compromise - its drop dead simple. This was the approach I was considering for Flux.
If you really want to work against latest working version of the pod, you can try using the Fantom compiler, but it wasn't really designed as an IDE compiler with error correction, etc (something which we've discussed a lot previously).
andySat 21 Nov 2009
I used the normal Fantom compiler for the AST viewer, so its only useful if the code actually compiles, so not sure thats what you want.
tcolarSat 21 Nov 2009
Ok, that's what I thought.
Using FPod is very easy, the trickier part right now is figuring out the Type the completion is being called on ... since it's in an uncompiled(and probably uncompilable at that moment) source. (example : amethod().somefield._)
Anyway I'm currently working on using ANTLR to try and figure out the termExpr / call chain and use that to try to determine the type, that's by far the hardest part.
tcolarTue 24 Nov 2009
Wanted to report a minor annoyance:
When using fpod.readFully(new ZipInputStream(fos)) it system.out LOTS of entries like this:
WARNING: unexpected file in pod: typedb.def
WARNING: unexpected file in pod: doc/ChangeLog.fandoc
WARNING: unexpected file in pod: doc/Faq.fandoc
WARNING: unexpected file in pod: x256/flux.png
brianTue 24 Nov 2009
@tcolar
Those are valid warnings because you probably don't want to be using readFully(ZipInputStream). That method is designed to read a script pod from memory where we are not expecting resource files to be in the stream.
Try using the constructor with a ZipFile and use readFully() and see if that works better for you.
tcolarWed 25 Nov 2009
Thanks, works good.
tcolarWed 25 Nov 2009
Did good progress on the completion. One more question, I love Fan featured to ask for existing Pod/Types.
Is there a similar easy built-in way to ask for the available Java types (JVM and lib/java/ext jars) ... otherwise i suppose i might be able to do it through the classloader.
brianWed 25 Nov 2009
Java doesn't provide much in the way of jar/package/class reflection.
You can take a look at a compilerJava::ClassPath which is a hack I wrote to deal with the issue for Java FFI.
tcolarThu 26 Nov 2009
Cool, I was able to use it directly this way:
FanObj classPath = (FanObj) Type.find("compilerJava::ClassPath").method("makeForCurrent").call();
Map map = (Map)classPath.type().field("classes").get(classPath);
String[] packages=(String[])map.keys().asArray(String.class);
for(String pack : packages)
{
String[] classes=(String[])((List)map.get(pack)).asArray(String.class);
// for real use I would store in a Java Map, but to test just system.out all
for(String clazz: classes)
System.out.println(pack+"."+clazz);
}
It's a bit ugly(casting) but it does the job.
Does that seem right or could I clean this a bit ?
brianThu 26 Nov 2009
Does that seem right or could I clean this a bit ?
Looks as right as you can make ugly Java reflection code.
tcolarSat 5 Dec 2009
For some of my Type determination stuff, I want to get the "Type" of a List of objects.
For example I can do this (java) fan.sys.Type listType = new fan.sys.List(resolved.getAsFanType(),0).type();
Where resolved.getAsFanType() is a FanType for example Str, so I want to get a Fan Type of type List of Str (Str[])
The line of code listed above works, but itt creates an actual list just to gets it's type, I'm sure I should be able to avoid to create an object to get a type, but I'm not sure about the syntax to do it.
maybe a Type.make("Str[]") or ListType.make(Str')' or something ?
Thanks.
tcolarSat 5 Dec 2009
Nevermind jut found Type.toListOf()
tcolarSat 5 Dec 2009
Ok, that works great for fan List of Fa objects (Fan)Type.toListOf()
Now I also need to deal with a Fan List of Java object (ex: String[]).... how do I get a Type for that ??
Can I somehow get a Fan Type from a Java Type and then call Type.toListOf() or is there something else.
I have the same questions for Map.
Need to do that kind of stuff for completion purposes (hard) in this case i want to know a Field /var Type, so I can later propose it's slot.
Thanks.
brianSat 5 Dec 2009
Not quite sure what you are trying to convert from and to, if you are trying to map java Classes to Fan types, then use fanx.util.FanUtil.toFanType (or its other utils):
FanUtil.toFanType(String.class).toListOf()
tcolarSat 5 Dec 2009
I guess I wasn't too clear.
What I'm trying to do at this point is looking for fields defined in the source code and store their name and type (say Int myvar).
So later if the user try to complete that field (myvar._) i can propose appropriate slots for that field type.
I got this working fine for simple types right now (both fan & ffi) as well as for List of Fan objects. (using either Fan's Type.find or Java reflection)
Now if I have a List or map of java objects such as:
using [java] com.corp.MyCoolClass
....
MyCoolClass[] listOfCoolClass
Str:MyCoolClass mapOfCoolClass
I'm able to resolve MyCoolClass as my java type just fine, but what i want is a Fan type (since it's a fan list) ... I expect this to be a Fan type representation of list of MyCoolClass.
This way when a user try to complete listOfCoolClass[0]._ I can propose the appropriate fields/methods of MyCoolClass.
I'll look into toFanType() but if I do toFanType(MyCoolClass.class) will I be able to reflect the Java methods/slots behind it ?
If yes then cool, I would use toFanType on my java types right away and be able to use Fan's reflection and not have to deal with java reflection much... if not then I still need help figuring out how to get the List of Java objects type.
Hope this is clear.
tcolarSat 5 Dec 2009
Also as a somewhat related question, could fantom.org somewhere have fandoc/javdoc for the java code of the Fan distribution. (and maybe other non-api stuff as well)
It's fairly well documented, but to look at it I have to dig through the source code, kinda slow and inefficient.
brianSat 5 Dec 2009
I don't think I am quite following you.
If you want the type of the items in the list, it is just sys::List.of.
But I suspect you might be heading down the wrong path. Consider that in the expr foo[bar], the resulting type doesn't have anything to do with List or Map, but is really just sugar for foo.get.
So if foo is Str[] and you parameterize get then you know foo[bar] evaluates to a Str.
So put another way, I think you will find it easier to break problems up:
foo[bar] // when you see this
foo.get(bar) // evaluate the type as this
Then you see a generic method you just need to substitue V, K, L, or M.
Make sense?
tcolarSat 5 Dec 2009
Ok i see FanUtil.toFanType(String.class) will give me a JavaType for a java class and that supports reflection so it's actually gonna be nice.
I was trying to carry a java type for java fields and a fan type for fan fields, but that's unnecessary I can always use fan's Type.
Cool, should make my code cleaner too.
As for your previous answer ... all i was trying to say is that when somebody tries to complete
someList._ i want to propose List slots while for:
somelist[0]._ i want to propose the List contained type slots ... point being I need to keep track of the contained type and was confused on how to do that for a java type ... but now that I see FanUtil.toFanType(String.class) can handle Java types and allow reflection I don't have a problem.
Anyway if that's still not clear, that's OK, you got me the info I needed :)
tcolarSun 6 Dec 2009
I now have slots proposal working.
I'm trying to make it look nice and doing fine.
One small questions. Slot as a method hasDefault() .. i'd like to show the default value in the proposal ... but there isn't any getDefault() ... any way to get to it ?
Thanks.
brianSun 6 Dec 2009
If the docs are available in the pod, you can get the string used by the fandoc:
fansh> Int#fromStr.doc
@checked.def=true
@radix.def=10
Parse a Str into a Int using the specified radix.
If invalid format and checked is false return null,
otherwise throw ParseErr.
I remember noticing those @.defs in the fandoc some time back, and thinking it meant they were being put on the slot as facets; quick check of slot.facets showed they're not. But it seemed like it might make sense to do that; is there a reason for/against? It'd obviously be useful for tools.
brianMon 7 Dec 2009
I remember noticing those @.defs in the fandoc some time back, and thinking it meant they were being put on the slot as facets
The general problem with docs as facets is that it can be really big and it requires an extra compilation phase, which is why I made it something separate.
You could argue that defs aren't just doc things, but I think since we are saving a doc string and not the actual expression, I definitely think of them as doc-only things. Although maybe some of this latest IDE work might shift that opinion.
tcolarTue 8 Dec 2009
I'm doing completion(good progress) and proposing the Slots for a given type to the user. This is working well, for example
When I show the returned Type, for example for a field I use: field.of() , for a method / constructor I use method.returns()
This work well for field/method
Now to the question:Method.returns for a constructor (make) is Void .... is this normal ? I would expect it to return the slot type, rather than void.
brianTue 8 Dec 2009
Now to the question: Method.returns for a constructor (make) is Void .... is this normal ? I would expect it to return the slot type, rather than void.
It is just part of constructors dual nature. On the outside they are static and return their declaring type. On the inside they are instance and void. As a general rule constructors override Slot methods for their inside behavior.
tcolarWed 9 Dec 2009
Another question: Are there any docs on what constitutes a scope in Fan (as far as variables scoping go), once in a method, is a scope always delimited by { and } ... or are there some other things that could be a scope ? - can't think of any right now, since itBlocks, closures etc.. all use {}.
Thanks.
brianThu 10 Dec 2009
nce in a method, is a scope always delimited by { and } ... or are there some other things that could be a scope
Pretty much like you'd expect - {} introduce a scope whether they are an if/else, for, while, try statement or an it-block/closure. Binding occurs in order of:
local variable or parameter
slots on implicit it
slots on implicit this
Also remember that like Java a for loop introduces a scope in its initializer expression:
for (i:=0; i<10; ++i) {...}
jodastephenThu 10 Dec 2009
Also remember that like Java a for loop introduces a scope in its initializer expression:
Do we need to have this additional rule? Could we simplify by saying that there is no new scope for i and if there is a conflict then the loop variable is a duplicate and an error. Seems like a useful simplification (the less rules the better).
brianThu 10 Dec 2009
Do we need to have this additional rule?
Considering that 99% of for loops use that technique it would really suck :-) I think it is something that programmers take for granted, but compiler writers just need to be aware of. BTW, this case also presents itself with catch clauses:
try
{
}
catch (Err e)
{
}
The e is introduced into the catch block scope only (but actually isn't really declared there).
heliumThu 10 Dec 2009
Do we need to have this additional rule?
YES!
tcolarThu 10 Dec 2009
Yeah and then there is try/catch without brackets to deal with as well. Anyhow, I'm probably going to release a version with completion within a week.
It will probably not handle EVERYTHING then, such as namedSuper, cast vars, it, for/try variables, but some completion is still way more useful than none so it's still good to start with.
BTW: In Fan I very rarely use a for loop yet, I much prefer 5.times{} or .each type loops etc...
Also loop vars are usually called something like i or j, and exception e, so completion really is not a big deal here, though I'll deal with it at some point, maybe not right away.
Anyway at this point I got completion working for
using statement, both java FFI and Fan (pod & type)
Fields and scoped variables, method parameters etc... which is already quite useful.
Still working on some things I want to have (such as super._ completion) and some aspects of inferred variables.
The nice thing is it shows the Fan/Slot fandoc along with the proposals, that's probably what I use completion for, just as much as saving some typing, especially for Fan where I'm not that used to the libraries yet.
tcolarFri 11 Dec 2009
Since JavaType.pod() returns null(expected), it would be nice if JavaType.podname was public or if there was a JavaType.getPodName() method.
Right now it seem to gte the java type podname, I have to get qname() and strip the type of.
brianSat 12 Dec 2009
it would be nice if JavaType.podname was public or if there was a JavaType.getPodName() method.
When I have a Java object that has a field marked transient, I can't seem to find that out from JavaType.
JavaType has no method isTransient(), alternatively maybe it should set a "transient" Facet on the JavaType if the underlaying Java field is transient.
It does not seem to be either, so I can't seem to know whether it's transient or not.
Couple more question. (Working on indexing compiled pods now), source done.
Q1: Given a FType I find the attributes such as: isOverride = hasFlag(ftype.flags, FConst.Override) // does a binary &
That works fine, except for "readonly" ... doesn't exist in FConst ... is it just missing(hardcoded) or is readonly maybe not a modifier(flag) but a facet or something ?
Q2: Given the FType, how do I figure whether it's a class, mixin or enum ? Maybe type.base or type.self are flags (unsure) ? or maybe in FTypeRef ?
I'd like to do it just with the (fanx.FType) I mean without using fan.Type.find() since I believe that works only with pre-cached pods that where present when fan runtime was started, in my case here i need to check new pods on the fly, which I do using fpod.readFully() Let me know If I'm wrong on that.
Thanks.
tcolarTue 29 Dec 2009
nevermind about Q1 (readonly), only need answer to Q2.
brianTue 29 Dec 2009
readonly is just sugar for private setter
FType.flags has flags both mixin and enum (lack of either flag means normal class)
tcolarTue 9 Mar 2010
As I'm going to work some more on type resolution / semantic analysis, I'd like to know where I can find info on:
Implicit casting -> when/how does it happens
Are there rules as far as type inference go, in particular if you do something like: i := 2 + 3.2 You probably get a Float
Are there any rules/doc on this, or do I need to dig into the compiler code ?
Thanks.
tacticsTue 9 Mar 2010
Implicit casting -> when/how does it happens
You mean this?
Obj a := Int#
Type b = a
echo(b.slots)
As far as I understand it, it happens whenever you make an assignment or pass a variable and the incomming type (Obj in this example) is a superclass of the expected type (Type above).
You probably don't have access to the fcode, but a Coerce instruction is automatically inserted by the compiler.
# Are there rules as far as type inference go, in particular if you do something like: i := 2 + 3.2 You probably get a Float
3.2 is actually a Decimal, not a Float. And there is no automatic arithmetic coercion. To get this to compile, you must use 2.toDecimal + 3.2.
KevinKelleyTue 9 Mar 2010
i := 2 + 3.2
That's an error actually; no implicit conversions. That would have to be either 2f + 3.2f and i becomes a Float; or 3.2.round and i is (Int)5. I can't find the doc ref for that though.
Kevin, thanks for the links (esp. docLang::TypeSystem#implicitCasts)
also it seem src/compiler/fan/steps/ResolveExpr.fan and src/compiler/fan/util/CallResolver.fan
Have most of the code dealing with that kind of stuff.
I guess my example was a bad one ... I meant that so far I had assume an inferred "expression" type can determined by it's "left-most" part ... but I'm just not sure whether it's always true.
KevinKelleyTue 9 Mar 2010
Pretty sure it's not "left-most", it's most-specific-that-fits, but I can't find what I'm remembering. I'd seen that somewhere in the ast stuff, though, I'm sure.
Edit: sorry, I think I was thinking of CType.common, which seems to be just for lists and maps. I think, for compound expressions, the shortcut conversion of a + b to a.call(b) applies, so then left-most is the effect.
brianWed 10 Mar 2010
As others have said, there is no coercion b/w different types in Fantom (such as Int to Float). Although there is implicit casting. The key issue is that casting b/w things like Int and Int? is actually a coercion in Java (long vs Long).
However, the FFI does do coercion - for example int to Int (long).
I'm writing some more using tests and running them against all of fantom distro code (src and examples) .. anbd finding a few more issues, so will keep coming up with questions in the short future :)
Couple more questions:
in fantom-1.0.51/examples/web/demo.fan at line 69, you got: new make(|This|? f) { f?.call(this) }
What is |This|? suppose to be? Is that a nullable function type, if so isn't a -> require nowadays, or is that something else.
What is the rule when it comes to import duplicates, for example in some source file you have: using fwt \n using dom
Now both of those pods have an "Event" type, I currently show an error, but i guess it's legal, do you juts pick whichever comes first ?
Thanks.
tacticsWed 10 Mar 2010
What is |This|? suppose to be?
Yes, that's a nullable function type.
Usually, what you want is to give f a default value like this:
new make(|This|? f := null)
{
f?.call(this)
}
(It looks like someone forgot the default when they wrote the demo class).
This way, if you don't provide a with block, you effectively have a default constructor.
What is the rule when it comes to import duplicates
When two pods import the same class, everything still compiles fine. However, if you want to actually reference/use the ambiguous class in your code, you must fully qualify it:
using dom
using fwt
const class Bar
{
static Void main()
{ }
static Void onDomEvent(dom::Event e)
{
echo("foo")
}
static Void onFwtEvent(fwt::Event e)
{
echo("bar")
}
}
Alternatively, you can specifically import one or another in a using statement, in which case it is clear which class you are referencing:
using dom
using fwt
using fwt::Event
const class Bar
{
static Void main()
{ }
static Void onFwtEvent(Event e)
{
echo("bar")
}
}
tcolarThu 11 Mar 2010
Another question:
in: fantom-1.0.51/src/build/fan/tasks/JdkTask.fan
JdkTask inherits from Task
However Task is not defined in a using, or in the same folder as JdkTask (one folder up)
Now my code is failing to resolve this, and I know the reason is because i was considering a pod to be "one folder" which obviously is not the case.
Anyway, the real question is: What is the proper way to find which pod a source file is a part of (since it doesn't have a package declaration as in java).
I've struggled with that before and put my "folder name as pod name" hack in place, but I knew that was not gonna work for long :)
Now for this to be usable in any env like my IDE and unit tests, I need a rule to resolve the pod name which does NOT depend of the fan runtime (typeDB and company) ...
Would the proper way be something like:
Recurse up until finding "build.fan" and parse podName out of it (I'm worried that this parsing could be fragile too).
brianThu 11 Mar 2010
The proper strategy is to walk up the directory tree until you find "build.fan" then use the information in that. The simplest thing to do is actually parse the build file, then construct it (but don't run it):
I converted that to java and it seem to be working ok ... except for the "examples" The build.fan in there is a buildScript rather than a buildPod ... and so does not have podName defined.
What am I to do in that case ?
KevinKelleyThu 11 Mar 2010
That build task doesn't produce a pod; the fan files under there will obey the scripting rules.
Which most often means, a file is compiled by itself; may contain several classes; may use any pods in the system. Podname is autogenerated, munged from the directory, but nothing much sees it.
#934 adds using `uri` so scripts can refer to other scripts; and docLang::Env and #1014 discussing it is relevant too.
tcolarThu 11 Mar 2010
Right, I'm not gonna index that or anything, but i'll do the same auto-generated podName thing for simplicity and consistency - at least for now.
brianThu 11 Mar 2010
What you probably want to do is check if the build script subclasses from BuildPod.
The examples build script subclasses from BuildScript.
tcolarFri 12 Mar 2010
If I compile this: Int[] list := [25, `jj`]
It does not complain ... I was wondering if that's legal .. it seem even runtime is fine with it.
brianFri 12 Mar 2010
It will compile Obj[] is automatically cast to Int[]. However it will fail at runtime:
Int[] list := [25, `jj`]
echo(list[0])
echo(list[1])
If you remember we had a long discussion about how to deal with list casts. We don't actually walk the list to check each item, however we do generate the appropriate array type in Java which traps all sorts of things at runtime.
Also see #986 which will change behavior to untyped lists and maps to be typed based on LHS declaration.
tcolarFri 12 Mar 2010
Right so in the IDE, it is the right thing to do to mark that as an error (if LHS types don't match declaration).
brianFri 12 Mar 2010
I personally don't think the IDE should be any more strict on error checking than the Fantom compiler since that might come back to bite you (although extra lint like warnings certainly wouldn't hurt).
tcolarMon 29 Mar 2010
I was doing profiling on my IDE and fixed all the hot spot, but I have one left I find odd.
I'm using Fantom runtime to check on the buildScript as we discussed earlier in this thread (as part of the pod resolution)
I want to check on what type of script it is (ie: buildpod vs buildscript)
Anyway I use this code
File buildFan = new File(folder, "build.fan");
fan.sys.File buildFile = new fan.sys.LocalFile(buildFan);
FanObj script = (FanObj) Env.cur().compileScript(buildFile).make();
String buildType = script.typeof().base().name();
This line: FanObj script = (FanObj) Env.cur().compileScript(buildFile).make(); takes over 10 seconds to execute (src/flux/flux/build.fan) !!
This seem very excessive for a small build file like that, any ideas ??
Note: I'll try to step through and see what exactly takes that long under the covers.
brianMon 29 Mar 2010
Is it 10sec the first time, or 10sec everytime?
The first time that method is called the compiler code is getting loaded into memory.
On my machine loading the compiler isn't 10sec, but maybe 1sec (long enough to notice). What I do in fansh is run a test compile in the background as soon as fansh is launched. By the time you've typed an expression into the fansh and hit enter, typically everything is already loaded.
tcolarMon 29 Mar 2010
You are right, it's just once ... but it takes way longer than 1sec here, around 9-10s. It's on my workstation too, which is a pretty quick machine (2 double core pentium D @3+MHz and 8GB ram).
I can live with it, since its juts once, but that just seem to be a long time.
brianMon 29 Mar 2010
If it is 10sec, then I'd say something else is wrong. How long does it take to execute a simple hello world fan script on your machine? Should be about the same time (since compiler is loaded).
tcolar Wed 19 Aug 2009
I started working on auto-completion in my Netbeans plugin. I'm starting with import completion.
Typically with NB this is done by indexing packages(pods) & types in source folders and/or libs folder.
I could do that with Fan (at least for the sources anyway), for libraries not sure yet what is the proper way to do it(reflection probably - will look how they do it for java) ... but I think I remember that Fan has it's own "Type database" ... would it make sense for me to use that instead of probably slower parsing/indexing ? Also does that "DB" contain all of the pods/types in the repo or just the ones that where "loaded".
If you think it makes sense to use the DB, any info on using it ?
Thanks.
brian Wed 19 Aug 2009
I think the simplest solution is to break things up into:
I am not sure how Java IDEs work, but I assume they "index" the entire project from source. I would expect that in a Fan IDE, only the current pod would be indexed by source, and external pods would use the pre-compiled pod files via reflection. In this model the IDE works like the compiler does - the compiler does type checking against pods, not source. So if you want to auto-completion for a new method in an external pod, then that pod needs to be compiled first. The seems to simplify the problem and should make for more efficient IDEs - they only need to index the current pod being worked on (by index I mean build an AST model).
To use reflection in the IDE, the simplest thing is to just use "sys.jar" and its Java implementation of the sys APIs. For example to call
Pod.find
, you can use the Java classfan.sys.Pod
. Using Fan APIs from Java is really straight forward. Just ensure that you set the "fan.home" system property before you load any classes from "sys.jar". Then everything is booted up in the static initializer forfan.sys.Sys
.What won't work today is reloading a pod which has been recompiled. But you might be able to handle this yourself in brute force fashion by flushing the classloader used to load sys, and then booting Fan up again.
You might also what to check out what Cheeser did for tradewinds since he is hosting a Fan runtime from Java.
tcolar Wed 19 Aug 2009
Right, compiled POds through type DB should be faster/more convenient than parsing. I would only parse sources for currently opened pods in the IDE most likely.
I'll investigate some more the reflection and see how it goes, if I can get it to work without needing a runtime that would be nice.
All see how that goes, I seem to remember that you could not change/define on the fly Java system properties, so I might have to spawn another VM / Fan runtime anyway.
The type database wiki page (which I can't seem to find anymore) said something along the line of "It will update change pods/types automatically at runtime", but i guess from what you just said that it does so only at BOOT time, right ?
Thanks.
brian Wed 19 Aug 2009
Yeap you can. Just need to do it before you load the Sys class.
Technically the typedb is one piece of the overall reflection subsystem. What you need and will be using isn't the typedb per se, but rather just the reflection APIs to Pod/Type/Slot definitions.
Although if you want, you might just drop down a level and instead of using the reflection APIs, use the code in
fanx.fcode
to parse the type/slot meta-data straight out the pod file and manage it yourself. This is basically what Pod/Type/Slot are doing - just building an in-memory model of the fcode and then eventually mapping it to Java classes. But note, just using reflection doesn't actually emit Java classes - this is one of the cool things about Fan, you can do reflection before the Java classes are actually emitted.tcolar Wed 19 Aug 2009
Sounds good, that should get me what I need.
I might go the fanx.fcode route, because it might make it easier to "reload" pod that changed (timestamp)
tcolar Wed 19 Aug 2009
Sorry, I forgot to ask this: Does the reflection API have access to the doc(fandoc), if not I might go back to using the sources, because it's definitely nice to have the fandoc to go along with the completion proposals.
Update: I guess FDoc in fanx is the answer.
brian Wed 19 Aug 2009
Yes, in Fan this is super simple:
In the pod it is stored in a very simple text file. See
fanx.fcode.FDoc
and the impls forPod.doc
andType.doc
tcolar Fri 4 Sep 2009
It would be nice if Pod.fan had a reload() method that would do the same as load() but not prevent loading if already in the cache(lazy cache).
I can't seem to extend/ use Pod to make it reload updated/new pods because of this and the fact much of it is not
public
.I guess I have to use FPod for now.
Also i find this a bit weird:
shouldn't readFully() rather be a static method that returns an FPod.
brian Fri 4 Sep 2009
The problem is that it would introduce an extremely confusing issue of what to do with existing instances and classes using the old Pod definition.
Reloading scripts is one thing (and we already do it), because each version of the pod gets its own unique pod name.
But well-defined pod modules don't work that way.
tcolar Fri 4 Sep 2009
OK. I should be alright with FPod for my purpose.
tcolar Thu 10 Sep 2009
I started working on completion. I have imports completion working now, and it shows the relevant "fandoc" for the selected pod/type in the completion windows which is nice.
The thing though is that Pod.doc & Type.doc returns the doc as plain text. For some detailed(syntax heavy) doc such as sys:Buff or sys::Depend, that looks quite ugly.
So anyway my question is:
Is there a method somewhere to parse the doc into HTML? I know Sidewalk does this, but is that code in the Fan distro.
I don't mind the Fandoc Syntax being the same as used in the fandev Wiki, but if the code to parse fandocs is not available in the fan distro, this is not useful / usable.
Thanks.
andy Thu 10 Sep 2009
There's an example in docLib.
tcolar Thu 10 Sep 2009
Thanks, i missed that somehow.
tcolar Thu 10 Sep 2009
One thing is that i need to run this from java, since it's a
pure
Fan library I can't call it directly like I do with fan classes implemented in Java(such as fanx.fcode.FPod).I have access to the fan user fan distro, so I guess I can "use" it
One way would be for me to do something like call a little fan script that return the doc like:
java fanx.tools.Fan fanIde.getDoc sys type
(with getDoc using FandocParser as in your example), it would work, but this seem quite inefficient (spawning vm's) and limited.I'm thinking maybe I could spawn One Fan shell process and interact with that, but I'm not sure if it's "capable" enough to return me what I need?
Any suggestion on a preferred way to do something like this (a.k.a using a Fan lib from Java) ?
andy Fri 11 Sep 2009
This is just a classloader issue, which I'm not sure we ever really cemented a design for. Brian can correct me, but I believe if you just use FanClassLoader to load the fandoc class into the same VM - then just use it directly - it will work. Thats not the long-term solution here though.
brian Fri 11 Sep 2009
@tcolar,
Since you already linking against sys.jar, I would suggest just using reflection to convert from fandoc to HTML. It is pretty "simple" using this code:
Don't you wish Java had a
->
operator!tcolar Sat 12 Sep 2009
Ha cool, the FanObj casting was the trick i was missing. Thanks. Same code in Fan would be so much shorter/cleaner !
tcolar Wed 23 Sep 2009
I'm trying to use this but I keep getting an error:
It errors out at this line:
sys.jar is loaded, so I'm not surer what's going on ?
Any clue ?
brian Wed 23 Sep 2009
Not really.
I tried that our snippet of Java code inside sys.jar and it worked.
might want to be some debug into FanClassLoader - something must be failing there
tcolar Wed 23 Sep 2009
I think I found what the deal was, i have two versions of fan, since at some point i was trying to build fan itself, I think this is where there is a mixup, though i'm not sure exactly how yet.
tcolar Fri 25 Sep 2009
Nevermind it still fails, I notice there is one error very first before the LineType one.
Does it make any more sense ?
KevinKelley Fri 25 Sep 2009
toImmutable
was one of the very recent changes, so it looks a lot like you've got some out of sync code somewhere. Using asys.jar
that's out of date?tcolar Fri 25 Sep 2009
Ok, I'll check that out. I don't think I do use another one, but maybe I put sys.jar in my classpath at some point for debugging or something.
tcolar Fri 25 Sep 2009
OK< i figures out the issue with sys.jar ... now i have a new weirdness.
Using same code here provided by Brian:
I do get the html printed out to stdout(presumably by the write method ?), but the html var is null ...
Maybe I'm just tired.
andy Sat 26 Sep 2009
HtmlDocWriter.make takes an
OutStream
as an arg with a default value ofSys.out
, so pass in a Buf to capture the output in memory.tcolar Mon 28 Sep 2009
Sorry for being thick, but i can't quite find something that work
Can't seem to find the proper way to pass a Buf to HtmlDocWriter.make, have tried many different things, but keep getting errors like:
andy Mon 28 Sep 2009
Just need to call
out
on Buf - try this:tcolar Mon 28 Sep 2009
Doh! Thanks, should have read the fandoc more carefully. As an aside, it would be nice if IllegalArgumentException exception was more detailed: Ex: Expected Outpustream but got Buf instead :)
brian Mon 28 Sep 2009
Fan doesn't generate that exception - it is raised by Java reflection and we just wrap it as ArgErr
tcolar Mon 28 Sep 2009
Ha, true, too bad.
tcolar Fri 20 Nov 2009
Ok, I'm working on this once again. I've decided to use the FPod facilities as the base for the completion, this proves to be very easy and practical!
Netbeans usually works fully from sources ... but working from sources is pretty difficult especially with a language like Fan with implicit casting, and inferred types etc. Also the indexing Netbeans uses, based on Lucene, appears buggy and doesn't seem to me like a very good solution for the completion job either.
Anyway, now the trick to this, is the code that's being "currently" worked on: It's not compiled yet, and potentially not compilable yet (incomplete code) ... so I still have to analyze the source for those, what I was wondering is whether there are built-in facilities in Fan that could help me .. say for example something to help me figure out and inferred variable Type and things like that.
I know Andy mentioned also working on some AST builder from fan source and was wondering if some of that might help me or if you have other suggestion on good ways to implement this (Since fan always seem to have some very nice built-in feature i miss at first)
If not, I'm going to start from my ANTLR built AST but will have to figure out lots of other things to get it to work right (like trying to figure out an inferred type).
Thanks.
brian Sat 21 Nov 2009
Well the simplest way would be use the fcode from the last successful compile. That obviously wouldn't pick up changes during the current cycle, but I expect would be a pretty good compromise - its drop dead simple. This was the approach I was considering for Flux.
If you really want to work against latest working version of the pod, you can try using the Fantom compiler, but it wasn't really designed as an IDE compiler with error correction, etc (something which we've discussed a lot previously).
andy Sat 21 Nov 2009
I used the normal Fantom compiler for the AST viewer, so its only useful if the code actually compiles, so not sure thats what you want.
tcolar Sat 21 Nov 2009
Ok, that's what I thought.
Using FPod is very easy, the trickier part right now is figuring out the Type the completion is being called on ... since it's in an uncompiled(and probably uncompilable at that moment) source. (example : amethod().somefield._)
Anyway I'm currently working on using ANTLR to try and figure out the termExpr / call chain and use that to try to determine the type, that's by far the hardest part.
tcolar Tue 24 Nov 2009
Wanted to report a minor annoyance:
When using
fpod.readFully(new ZipInputStream(fos))
it system.out LOTS of entries like this:brian Tue 24 Nov 2009
@tcolar
Those are valid warnings because you probably don't want to be using
readFully(ZipInputStream)
. That method is designed to read a script pod from memory where we are not expecting resource files to be in the stream.Try using the constructor with a
ZipFile
and usereadFully()
and see if that works better for you.tcolar Wed 25 Nov 2009
Thanks, works good.
tcolar Wed 25 Nov 2009
Did good progress on the completion. One more question, I love Fan featured to ask for existing Pod/Types.
Is there a similar easy built-in way to ask for the available Java types (JVM and lib/java/ext jars) ... otherwise i suppose i might be able to do it through the classloader.
brian Wed 25 Nov 2009
Java doesn't provide much in the way of jar/package/class reflection.
You can take a look at a compilerJava::ClassPath which is a hack I wrote to deal with the issue for Java FFI.
tcolar Thu 26 Nov 2009
Cool, I was able to use it directly this way:
It's a bit ugly(casting) but it does the job.
Does that seem right or could I clean this a bit ?
brian Thu 26 Nov 2009
Looks as right as you can make ugly Java reflection code.
tcolar Sat 5 Dec 2009
For some of my Type determination stuff, I want to get the "Type" of a List of objects.
For example I can do this (java)
fan.sys.Type listType = new fan.sys.List(resolved.getAsFanType(),0).type();
Where
resolved.getAsFanType()
is a FanType for exampleStr
, so I want to get a Fan Type of type List of Str (Str[])The line of code listed above works, but itt creates an actual list just to gets it's type, I'm sure I should be able to avoid to create an object to get a type, but I'm not sure about the syntax to do it.
maybe a
Type.make("Str[]")
orListType.make(
Str')' or something ?Thanks.
tcolar Sat 5 Dec 2009
Nevermind jut found Type.toListOf()
tcolar Sat 5 Dec 2009
Ok, that works great for fan List of Fa objects (Fan)Type.toListOf()
Now I also need to deal with a Fan List of Java object (ex:
String[]
).... how do I get a Type for that ??Can I somehow get a Fan Type from a Java Type and then call Type.toListOf() or is there something else.
I have the same questions for Map.
Need to do that kind of stuff for completion purposes (hard) in this case i want to know a Field /var Type, so I can later propose it's slot.
Thanks.
brian Sat 5 Dec 2009
Not quite sure what you are trying to convert from and to, if you are trying to map java Classes to Fan types, then use
fanx.util.FanUtil.toFanType
(or its other utils):tcolar Sat 5 Dec 2009
I guess I wasn't too clear.
What I'm trying to do at this point is looking for fields defined in the source code and store their name and type (say Int myvar).
So later if the user try to complete that field (myvar._) i can propose appropriate slots for that field type.
I got this working fine for simple types right now (both fan & ffi) as well as for List of Fan objects. (using either Fan's Type.find or Java reflection)
Now if I have a List or map of java objects such as:
I'm able to resolve MyCoolClass as my java type just fine, but what i want is a Fan type (since it's a fan list) ... I expect this to be a Fan type representation of list of MyCoolClass.
This way when a user try to complete
listOfCoolClass[0]._
I can propose the appropriate fields/methods of MyCoolClass.I'll look into toFanType() but if I do toFanType(MyCoolClass.class) will I be able to reflect the Java methods/slots behind it ?
If yes then cool, I would use toFanType on my java types right away and be able to use Fan's reflection and not have to deal with java reflection much... if not then I still need help figuring out how to get the List of Java objects type.
Hope this is clear.
tcolar Sat 5 Dec 2009
Also as a somewhat related question, could fantom.org somewhere have fandoc/javdoc for the java code of the Fan distribution. (and maybe other non-api stuff as well)
It's fairly well documented, but to look at it I have to dig through the source code, kinda slow and inefficient.
brian Sat 5 Dec 2009
I don't think I am quite following you.
If you want the type of the items in the list, it is just
sys::List.of
.Also might want take a look at
sys::Type.params
But I suspect you might be heading down the wrong path. Consider that in the expr
foo[bar]
, the resulting type doesn't have anything to do with List or Map, but is really just sugar forfoo.get
.So if foo is
Str[]
and you parameterizeget
then you knowfoo[bar]
evaluates to a Str.So put another way, I think you will find it easier to break problems up:
Then you see a generic method you just need to substitue V, K, L, or M.
Make sense?
tcolar Sat 5 Dec 2009
Ok i see FanUtil.toFanType(String.class) will give me a JavaType for a java class and that supports reflection so it's actually gonna be nice.
I was trying to carry a java type for java fields and a fan type for fan fields, but that's unnecessary I can always use fan's Type.
Cool, should make my code cleaner too.
As for your previous answer ... all i was trying to say is that when somebody tries to complete
someList._
i want to propose List slots while for:somelist[0]._
i want to propose the List contained type slots ... point being I need to keep track of the contained type and was confused on how to do that for a java type ... but now that I see FanUtil.toFanType(String.class) can handle Java types and allow reflection I don't have a problem.Anyway if that's still not clear, that's OK, you got me the info I needed :)
tcolar Sun 6 Dec 2009
I now have slots proposal working.
I'm trying to make it look nice and doing fine.
One small questions. Slot as a method hasDefault() .. i'd like to show the default value in the proposal ... but there isn't any getDefault() ... any way to get to it ?
Thanks.
brian Sun 6 Dec 2009
If the docs are available in the pod, you can get the string used by the fandoc:
See docCompiler for how to parse it.
KevinKelley Sun 6 Dec 2009
I remember noticing those
@.def
s in the fandoc some time back, and thinking it meant they were being put on the slot as facets; quick check ofslot.facets
showed they're not. But it seemed like it might make sense to do that; is there a reason for/against? It'd obviously be useful for tools.brian Mon 7 Dec 2009
The general problem with docs as facets is that it can be really big and it requires an extra compilation phase, which is why I made it something separate.
You could argue that defs aren't just doc things, but I think since we are saving a doc string and not the actual expression, I definitely think of them as doc-only things. Although maybe some of this latest IDE work might shift that opinion.
tcolar Tue 8 Dec 2009
I'm doing completion(good progress) and proposing the Slots for a given type to the user. This is working well, for example
When I show the returned Type, for example for a field I use:
field.of()
, for a method / constructor I usemethod.returns()
This work well for field/method
Now to the question:
Method.returns
for a constructor (make) isVoid
.... is this normal ? I would expect it to return the slot type, rather than void.brian Tue 8 Dec 2009
It is just part of constructors dual nature. On the outside they are static and return their declaring type. On the inside they are instance and void. As a general rule constructors override Slot methods for their inside behavior.
tcolar Wed 9 Dec 2009
Another question: Are there any docs on what constitutes a scope in Fan (as far as variables scoping go), once in a method, is a scope always delimited by
{
and}
... or are there some other things that could be a scope ? - can't think of any right now, since itBlocks, closures etc.. all use{}
.Thanks.
brian Thu 10 Dec 2009
Pretty much like you'd expect -
{}
introduce a scope whether they are an if/else, for, while, try statement or an it-block/closure. Binding occurs in order of:Also remember that like Java a
for
loop introduces a scope in its initializer expression:jodastephen Thu 10 Dec 2009
Do we need to have this additional rule? Could we simplify by saying that there is no new scope for
i
and if there is a conflict then the loop variable is a duplicate and an error. Seems like a useful simplification (the less rules the better).brian Thu 10 Dec 2009
Considering that 99% of for loops use that technique it would really suck :-) I think it is something that programmers take for granted, but compiler writers just need to be aware of. BTW, this case also presents itself with catch clauses:
The e is introduced into the catch block scope only (but actually isn't really declared there).
helium Thu 10 Dec 2009
YES!
tcolar Thu 10 Dec 2009
Yeah and then there is try/catch without brackets to deal with as well. Anyhow, I'm probably going to release a version with completion within a week.
It will probably not handle EVERYTHING then, such as namedSuper, cast vars, it, for/try variables, but some completion is still way more useful than none so it's still good to start with.
BTW: In Fan I very rarely use a for loop yet, I much prefer 5.times{} or .each type loops etc...
Also loop vars are usually called something like
i
orj
, and exceptione
, so completion really is not a big deal here, though I'll deal with it at some point, maybe not right away.Anyway at this point I got completion working for
using
statement, both java FFI and Fan (pod & type)Still working on some things I want to have (such as super._ completion) and some aspects of inferred variables.
The nice thing is it shows the Fan/Slot fandoc along with the proposals, that's probably what I use completion for, just as much as saving some typing, especially for Fan where I'm not that used to the libraries yet.
tcolar Fri 11 Dec 2009
Since JavaType.pod() returns null(expected), it would be nice if JavaType.podname was public or if there was a JavaType.getPodName() method.
Right now it seem to gte the java type podname, I have to get qname() and strip the type of.
brian Sat 12 Dec 2009
added JavaType.podName() - changeset
tcolar Thu 17 Dec 2009
Another thing about Fantom's JavaType:
When I have a Java object that has a field marked transient, I can't seem to find that out from JavaType.
JavaType has no method
isTransient()
, alternatively maybe it should set a "transient" Facet on the JavaType if the underlaying Java field is transient.It does not seem to be either, so I can't seem to know whether it's transient or not.
brian Thu 17 Dec 2009
I pushed a fix - try that out
tcolar Thu 17 Dec 2009
Thanks.
tcolar Tue 29 Dec 2009
Couple more question. (Working on indexing compiled pods now), source done.
Q1: Given a FType I find the attributes such as: isOverride = hasFlag(ftype.flags, FConst.Override) // does a binary &
That works fine, except for "readonly" ... doesn't exist in FConst ... is it just missing(hardcoded) or is readonly maybe not a modifier(flag) but a facet or something ?
Q2: Given the FType, how do I figure whether it's a class, mixin or enum ? Maybe type.base or type.self are flags (unsure) ? or maybe in FTypeRef ?
I'd like to do it just with the (fanx.FType) I mean without using fan.Type.find() since I believe that works only with
pre-cached
pods that where present when fan runtime was started, in my case here i need to check new pods on the fly, which I do using fpod.readFully() Let me know If I'm wrong on that.Thanks.
tcolar Tue 29 Dec 2009
nevermind about Q1 (readonly), only need answer to Q2.
brian Tue 29 Dec 2009
tcolar Tue 9 Mar 2010
As I'm going to work some more on type resolution / semantic analysis, I'd like to know where I can find info on:
i := 2 + 3.2
You probably get a FloatAre there any rules/doc on this, or do I need to dig into the compiler code ?
Thanks.
tactics Tue 9 Mar 2010
You mean this?
As far as I understand it, it happens whenever you make an assignment or pass a variable and the incomming type (
Obj
in this example) is a superclass of the expected type (Type
above).You probably don't have access to the fcode, but a
Coerce
instruction is automatically inserted by the compiler.3.2
is actually aDecimal
, not aFloat
. And there is no automatic arithmetic coercion. To get this to compile, you must use2.toDecimal + 3.2
.KevinKelley Tue 9 Mar 2010
That's an error actually; no implicit conversions. That would have to be either
2f + 3.2f
and i becomes a Float; or3.2.round
and i is (Int)5. I can't find the doc ref for that though.These two pages are useful:
docLang::Expressions#typeChecking
docLang::TypeSystem#implicitCasts
tcolar Tue 9 Mar 2010
Kevin, thanks for the links (esp. docLang::TypeSystem#implicitCasts)
also it seem src/compiler/fan/steps/ResolveExpr.fan and src/compiler/fan/util/CallResolver.fan
Have most of the code dealing with that kind of stuff.
I guess my example was a bad one ... I meant that so far I had assume an inferred "expression" type can determined by it's "left-most" part ... but I'm just not sure whether it's always true.
KevinKelley Tue 9 Mar 2010
Pretty sure it's not "left-most", it's most-specific-that-fits, but I can't find what I'm remembering. I'd seen that somewhere in the ast stuff, though, I'm sure.
Edit: sorry, I think I was thinking of
CType.common
, which seems to be just for lists and maps. I think, for compound expressions, the shortcut conversion ofa + b
toa.call(b)
applies, so then left-most is the effect.brian Wed 10 Mar 2010
As others have said, there is no coercion b/w different types in Fantom (such as Int to Float). Although there is implicit casting. The key issue is that casting b/w things like
Int
andInt?
is actually a coercion in Java (long vs Long).However, the FFI does do coercion - for example int to Int (long).
Good place to look is
compiler::CheckErrors.coerce
and the associated boxing methods.tcolar Wed 10 Mar 2010
I'm writing some more using tests and running them against all of fantom distro code (src and examples) .. anbd finding a few more issues, so will keep coming up with questions in the short future :)
Couple more questions:
new make(|This|? f) { f?.call(this) }
What is
|This|?
suppose to be? Is that a nullable function type, if so isn't a->
require nowadays, or is that something else.using fwt
\nusing dom
Now both of those pods have an "Event" type, I currently show an error, but i guess it's legal, do you juts pick
whichever comes first
?Thanks.
tactics Wed 10 Mar 2010
Yes, that's a nullable function type.
Usually, what you want is to give
f
a default value like this:(It looks like someone forgot the default when they wrote the demo class).
This way, if you don't provide a with block, you effectively have a default constructor.
When two pods import the same class, everything still compiles fine. However, if you want to actually reference/use the ambiguous class in your code, you must fully qualify it:
Alternatively, you can specifically import one or another in a
using
statement, in which case it is clear which class you are referencing:tcolar Thu 11 Mar 2010
Another question:
in: fantom-1.0.51/src/build/fan/tasks/JdkTask.fan
JdkTask
inherits fromTask
However
Task
is not defined in a using, or in the same folder asJdkTask
(one folder up)Now my code is failing to resolve this, and I know the reason is because i was considering a pod to be "one folder" which obviously is not the case.
Anyway, the real question is: What is the proper way to find which pod a source file is a part of (since it doesn't have a
package
declaration as in java).I've struggled with that before and put my "folder name as pod name" hack in place, but I knew that was not gonna work for long :)
Now for this to be usable in any env like my IDE and unit tests, I need a rule to resolve the pod name which does NOT depend of the fan runtime (typeDB and company) ...
Would the proper way be something like:
Recurse up until finding "build.fan" and parse
podName
out of it (I'm worried that thisparsing
could be fragile too).brian Thu 11 Mar 2010
The proper strategy is to walk up the directory tree until you find "build.fan" then use the information in that. The simplest thing to do is actually parse the build file, then construct it (but don't run it):
tcolar Thu 11 Mar 2010
I converted that to java and it seem to be working ok ... except for the "examples" The build.fan in there is a buildScript rather than a buildPod ... and so does not have podName defined.
What am I to do in that case ?
KevinKelley Thu 11 Mar 2010
That build task doesn't produce a pod; the fan files under there will obey the scripting rules.
Which most often means, a file is compiled by itself; may contain several classes; may use any pods in the system. Podname is autogenerated, munged from the directory, but nothing much sees it.
#934 adds
using `uri`
so scripts can refer to other scripts; and docLang::Env and #1014 discussing it is relevant too.tcolar Thu 11 Mar 2010
Right, I'm not gonna index that or anything, but i'll do the same auto-generated podName thing for simplicity and consistency - at least for now.
brian Thu 11 Mar 2010
What you probably want to do is check if the build script subclasses from BuildPod.
The examples build script subclasses from BuildScript.
tcolar Fri 12 Mar 2010
If I compile this:
Int[] list := [25, `jj`]
It does not complain ... I was wondering if that's legal .. it seem even runtime is fine with it.
brian Fri 12 Mar 2010
It will compile
Obj[]
is automatically cast toInt[]
. However it will fail at runtime:If you remember we had a long discussion about how to deal with list casts. We don't actually walk the list to check each item, however we do generate the appropriate array type in Java which traps all sorts of things at runtime.
Also see #986 which will change behavior to untyped lists and maps to be typed based on LHS declaration.
tcolar Fri 12 Mar 2010
Right so in the IDE, it is the right thing to do to mark that as an error (if LHS types don't match declaration).
brian Fri 12 Mar 2010
I personally don't think the IDE should be any more strict on error checking than the Fantom compiler since that might come back to bite you (although extra lint like warnings certainly wouldn't hurt).
tcolar Mon 29 Mar 2010
I was doing profiling on my IDE and fixed all the hot spot, but I have one left I find odd.
I'm using Fantom runtime to check on the buildScript as we discussed earlier in this thread (as part of the pod resolution)
I want to check on what type of script it is (ie: buildpod vs buildscript)
Anyway I use this code
This line:
FanObj script = (FanObj) Env.cur().compileScript(buildFile).make();
takes over 10 seconds to execute (src/flux/flux/build.fan) !!This seem very excessive for a small build file like that, any ideas ??
Note: I'll try to step through and see what exactly takes that long under the covers.
brian Mon 29 Mar 2010
Is it 10sec the first time, or 10sec everytime?
The first time that method is called the compiler code is getting loaded into memory.
On my machine loading the compiler isn't 10sec, but maybe 1sec (long enough to notice). What I do in fansh is run a test compile in the background as soon as fansh is launched. By the time you've typed an expression into the fansh and hit enter, typically everything is already loaded.
tcolar Mon 29 Mar 2010
You are right, it's just once ... but it takes way longer than 1sec here, around 9-10s. It's on my workstation too, which is a pretty quick machine (2 double core pentium D @3+MHz and 8GB ram).
I can live with it, since its juts once, but that just seem to be a long time.
brian Mon 29 Mar 2010
If it is 10sec, then I'd say something else is wrong. How long does it take to execute a simple hello world fan script on your machine? Should be about the same time (since compiler is loaded).